You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解码BitTorrent v2种子文件info元数据的二进制pieces root?

BitTorrent v2 提取pieces root哈希的实现方案(PHP/C)

核心背景回顾

BitTorrent v2的种子文件采用Bencode编码,info元数据中的pieces root是二进制形式的SHA256默克尔根,由16KiB块构建二叉默克尔树(末尾块不足16KiB时补零)。我们需要把这个二进制哈希转成十六进制字符串,用于网页展示。


PHP实现方案(新手友好)

步骤1:解析Bencode格式的种子文件

BT种子是Bencode编码的键值对结构,必须先解析才能拿到info里的pieces root。下面是一个简化版的Bencode解析函数(仅处理我们需要的字典、字符串类型):

function bdecode($data) {
    $pos = 0;
    $len = strlen($data);
    
    $decode = function() use (&$data, &$pos, &$len, &$decode) {
        if ($pos >= $len) return null;
        $c = $data[$pos];
        
        // 处理字符串:格式为 "数字:内容",例 "10:helloworld"
        if (ctype_digit($c)) {
            $colon_pos = strpos($data, ':', $pos);
            $str_len = (int)substr($data, $pos, $colon_pos - $pos);
            $pos = $colon_pos + 1;
            $str = substr($data, $pos, $str_len);
            $pos += $str_len;
            return $str;
        }
        // 处理字典:格式为 "d键值对e"
        elseif ($c === 'd') {
            $pos++;
            $dict = [];
            while ($data[$pos] !== 'e') {
                $key = $decode();
                $value = $decode();
                $dict[$key] = $value;
            }
            $pos++;
            return $dict;
        }
        return null;
    };
    
    return $decode();
}

步骤2:读取种子并提取pieces root

// 1. 读取种子文件内容
$torrent_content = file_get_contents('your_torrent_file.torrent');
if (!$torrent_content) {
    die('无法读取种子文件');
}

// 2. 解析Bencode数据
$torrent_data = bdecode($torrent_content);
if (!isset($torrent_data['info']['pieces root'])) {
    die('该种子不是BitTorrent v2格式,无pieces root字段');
}

// 3. 提取二进制哈希并转十六进制
$pieces_root_bin = $torrent_data['info']['pieces root'];
// 用bin2hex直接转十六进制,比unpack更简单
$pieces_root_hex = bin2hex($pieces_root_bin);

// 输出结果(用于网页展示)
echo 'Pieces Root哈希:' . $pieces_root_hex;

关于unpack失败的原因

如果一定要用unpack,正确写法是:

$pieces_root_hex = implode('', unpack('H*', $pieces_root_bin));

unpack('H*', $bin)会返回一个数组,每个元素是十六进制片段,必须用implode拼接成完整字符串,之前大概率是没做拼接导致失败。


C语言实现方案(新手友好)

步骤1:核心思路

C语言需要手动解析Bencode,读取种子文件后定位info字典里的pieces root字段,再将二进制哈希转成十六进制字符串。

步骤2:完整代码实现(带注释)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// 读取整个文件到内存
char* read_file(const char* filename, size_t* file_len) {
    FILE* fp = fopen(filename, "rb");
    if (!fp) {
        perror("无法打开种子文件");
        return NULL;
    }
    
    // 获取文件大小
    fseek(fp, 0, SEEK_END);
    *file_len = ftell(fp);
    fseek(fp, 0, SEEK_SET);
    
    // 分配内存并读取
    char* buffer = malloc(*file_len + 1);
    if (!buffer) {
        perror("内存分配失败");
        fclose(fp);
        return NULL;
    }
    fread(buffer, 1, *file_len, fp);
    fclose(fp);
    buffer[*file_len] = '\0';
    return buffer;
}

// 解析Bencode字符串(返回内容,更新pos到字符串结束位置)
char* bdecode_string(const char* data, size_t* pos) {
    // 读取字符串长度数字
    size_t len = 0;
    while (isdigit(data[*pos])) {
        len = len * 10 + (data[*pos] - '0');
        (*pos)++;
    }
    if (data[*pos] != ':') return NULL; // 格式错误
    (*pos)++; // 跳过冒号
    
    // 分配内存存储字符串
    char* str = malloc(len + 1);
    if (!str) return NULL;
    memcpy(str, data + *pos, len);
    str[len] = '\0';
    (*pos) += len;
    return str;
}

// 解析Bencode字典,找到指定key的value
void bdecode_dict_find(const char* data, size_t* pos, const char* target_key, char** out_value, size_t* out_len) {
    if (data[*pos] != 'd') return; // 不是字典
    (*pos)++; // 跳过'd'
    
    while (data[*pos] != 'e') {
        // 解析key
        char* key = bdecode_string(data, pos);
        if (!key) break;
        
        // 解析value(只处理字符串类型)
        char* value = NULL;
        size_t value_len = 0;
        if (isdigit(data[*pos])) {
            value = bdecode_string(data, pos);
            value_len = strlen(value);
        } else {
            // 跳过非字符串类型的value
            while (data[*pos] != 'e' && !isdigit(data[*pos])) {
                (*pos)++;
            }
        }
        
        // 匹配目标key
        if (strcmp(key, target_key) == 0) {
            *out_value = value;
            *out_len = value_len;
            free(key);
            return;
        }
        
        free(key);
        if (value) free(value);
    }
    (*pos)++; // 跳过'e'
}

// 二进制转十六进制字符串
char* bin_to_hex(const unsigned char* bin, size_t bin_len) {
    char* hex = malloc(bin_len * 2 + 1);
    if (!hex) return NULL;
    
    const char* hex_chars = "0123456789abcdef";
    for (size_t i = 0; i < bin_len; i++) {
        hex[i*2] = hex_chars[(bin[i] >> 4) & 0x0F];
        hex[i*2+1] = hex_chars[bin[i] & 0x0F];
    }
    hex[bin_len*2] = '\0';
    return hex;
}

int main() {
    const char* torrent_path = "your_torrent_file.torrent";
    size_t file_len;
    char* torrent_data = read_file(torrent_path, &file_len);
    if (!torrent_data) return 1;
    
    size_t pos = 0;
    // 先定位info字典
    char* info_data = NULL;
    size_t info_len = 0;
    bdecode_dict_find(torrent_data, &pos, "info", &info_data, &info_len);
    if (!info_data) {
        printf("种子文件格式错误,找不到info字段\n");
        free(torrent_data);
        return 1;
    }
    
    // 在info字典里找pieces root
    pos = 0;
    char* pieces_root_bin = NULL;
    size_t pieces_root_len = 0;
    bdecode_dict_find(info_data, &pos, "pieces root", &pieces_root_bin, &pieces_root_len);
    if (!pieces_root_bin) {
        printf("该种子不是BitTorrent v2格式,无pieces root字段\n");
        free(info_data);
        free(torrent_data);
        return 1;
    }
    
    // 转十六进制并输出
    char* pieces_root_hex = bin_to_hex((unsigned char*)pieces_root_bin, pieces_root_len);
    if (pieces_root_hex) {
        printf("Pieces Root哈希:%s\n", pieces_root_hex);
        free(pieces_root_hex);
    }
    
    // 释放内存
    free(pieces_root_bin);
    free(info_data);
    free(torrent_data);
    return 0;
}

编译与运行

  1. 将代码保存为bt_v2_extract.c
  2. 用GCC编译:gcc bt_v2_extract.c -o bt_v2_extract
  3. 运行:./bt_v2_extract(Windows下为bt_v2_extract.exe),记得替换代码中的种子文件路径。

内容的提问来源于stack exchange,提问作者greenandgreen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.03 14:50:21