|
本帖最后由 Mr.lin 于 2024-4-10 03:25 编辑
前言
众所周知 GoodSync 文件名加密算法不公开, 它们只提到 AES 加密
当我决定切换同步工具的时候遇到了这个问题, 大量文件加密传到云端, 不使用 GoodSync 无法解密文件名
我马上开一个工单去问它们客服, 态度屌的一批
为了解决问题, 更好配合 rclone 之类的同步工具, 我们开始分析
不想看分析的直接拉到底, 下载加解密工具
加密部分逆向分析
[ol]000000014014BF40 | 40:53 | push rbx |000000014014BF42 | 55 | push rbp |000000014014BF43 | 56 | push rsi | 000000014014BF44 | 57 | push rdi |000000014014BF45 | 41:54 | push r12 | 000000014014BF47 | 41:55 | push r13 |000000014014BF49 | 41:56 | push r14 |000000014014BF4B | 41:57 | push r15 |000000014014BF4D | 48:81EC A8000000 | sub rsp,A8 |000000014014BF54 | 48:C74424 58 FEFF | mov qword ptr ss:[rsp+58],FFFFFFFFFFFF |000000014014BF5D | 48:8B05 1426AF00 | mov rax,qword ptr ds:[140C3E578] |000000014014BF64 | 48:33C4 | xor rax,rsp |....000000014014BF83 | C64424 40 00 | mov byte ptr ss:[rsp+40],0 |000000014014BF88 | 48:8D5424 40 | lea rdx,qword ptr ss:[rsp+40] |000000014014BF8D | E8 1EEFFFFF | call gsexplorer.14014AEB0 | gen_salt_seek 易见, 该函数根据加密数据生成一个字节 存入 qword ptr ss:[rsp+40]000000014014BF92 | E8 591F1F00 | call gsexplorer.14033DEF0 | EVP_aes_256_cbc AES 加密000000014014BF97 | 48:894424 48 | mov qword ptr ss:[rsp+48],rax | 000000014014BF9C | E8 7FEC1E00 | call gsexplorer.14033AC20 |000000014014BFA1 | 48:8BD8 | mov rbx,rax |000000014014BFA4 | 48:894424 50 | mov qword ptr ss:[rsp+50],rax |000000014014BFA9 | 48:8BC8 | mov rcx,rax | 000000014014BFAC | E8 4FED1E00 | call gsexplorer.14033AD00 |000000014014BFB1 | 33FF | xor edi,edi |000000014014BFB3 | 8BD7 | mov edx,edi | 000000014014BFB5 | 4C:8D4424 60 | lea r8,qword ptr ss:[rsp+60] | 注意 salt, 生成过程000000014014BFBA | 44:0FB64C24 40 | movzx r9d,byte ptr ss:[rsp+40] | r9d 为之前生成 salt seek, 见上 qword ptr ss:[rsp+40]000000014014BFC0 | 0FB6C2 | movzx eax,dl |000000014014BFC3 | 6BC8 07 | imul ecx,eax,7 | edx: salt 索引 * 7000000014014BFC6 | 41:02C9 | add cl,r9b | 上步结果与 r9b 相加存入 ecx000000014014BFC9 | 41:8808 | mov byte ptr ds:[r8],cl | salt 数组每位 ecx000000014014BFCC | FFC2 | inc edx | 000000014014BFCE | 4D:8D40 01 | lea r8,qword ptr ds:[r8+1] |000000014014BFD2 | 83FA 08 | cmp edx,8 | slat 8 位000000014014BFD5 | 7C E9 | jl gsexplorer.14014BFC0 | 该循环生成 salt000000014014BFD7 | 48:8B6D 00 | mov rbp,qword ptr ss:[rbp] | ...000000014014C002 | 8BF0 | mov esi,eax | 000000014014C004 | E8 87171E00 | call gsexplorer.14032D790 | EVP_sha1000000014014C009 | 48:8BD0 | mov rdx,rax | 000000014014C00C | 48:8D4424 68 | lea rax,qword ptr ss:[rsp+68] |000000014014C011 | 48:894424 38 | mov qword ptr ss:[rsp+38],rax |000000014014C016 | 48:8D4424 78 | lea rax,qword ptr ss:[rsp+78] |000000014014C01B | 48:894424 30 | mov qword ptr ss:[rsp+30],rax | count000000014014C020 | C74424 28 0004000 | mov dword ptr ss:[rsp+28],400 | data_len000000014014C028 | 897424 20 | mov dword ptr ss:[rsp+20],esi |000000014014C02C | 4C:8BCD | mov r9,rbp |000000014014C02F | 4C:8D4424 60 | lea r8,qword ptr ss:[rsp+60] |000000014014C034 | 48:8B7424 48 | mov rsi,qword ptr ss:[rsp+48] | 000000014014C039 | 48:8BCE | mov rcx,rsi | 000000014014C03C | E8 EFE51E00 | call gsexplorer.14033A630 | EVP_BytesToKey 计算 key 和 iv000000014014C041 | 85C0 | test eax,eax |...000000014014C086 | 48:8BCB | mov rcx,rbx | 000000014014C089 | E8 02F81E00 | call gsexplorer.14033B890 | EVP_EncryptInit_ex 初始化加密方法000000014014C08E | 83F8 01 | cmp eax,1 |000000014014C091 | 74 2C | je gsexplorer.14014C0BF |000000014014C093 | 41:C706 06000000 | mov dword ptr ds:[r14],6 |...000000014014C15A | 4C:8D4424 44 | lea r8,qword ptr ss:[rsp+44] |000000014014C15F | 48:8BD6 | mov rdx,rsi | rsi000000014014C162 | 48:8B5C24 50 | mov rbx,qword ptr ss:[rsp+50] |000000014014C167 | 48:8BCB | mov rcx,rbx | rcx:&"gs_zipfs_state"000000014014C16A | E8 51F71E00 | call gsexplorer.14033B8C0 | EVP_EncryptUpdate 加密数据段000000014014C16F | 48:637C24 44 | movsxd rdi,dword ptr ss:[rsp+44] |000000014014C174 | 48:8D143E | lea rdx,qword ptr ds:[rsi+rdi] | 000000014014C178 | 4C:8D4424 44 | lea r8,qword ptr ss:[rsp+44] |000000014014C17D | 48:8BCB | mov rcx,rbx | rcx:&"gs_zipfs_state"000000014014C180 | E8 9BF51E00 | call gsexplorer.14033B720 | EVP_EncryptFinal_ex000000014014C185 | 037C24 44 | add edi,dword ptr ss:[rsp+44] |000000014014C189 | 4C:63C7 | movsxd r8,edi |000000014014C18C | 0FB64424 40 | movzx eax,byte ptr ss:[rsp+40] | 000000014014C191 | 41:880430 | mov byte ptr ds:[r8+rsi],al | 最后将 salt seek 加入最后一个字节, 准备解密000000014014C195 | FFC7 | inc edi |000000014014C197 | 8BD7 | mov edx,edi | 000000014014C199 | 49:8BCF | mov rcx,r15 | rcx:&"gs_zipfs_state"000000014014C19C | E8 DF02EEFF | call gsexplorer.14002C480 |000000014014C1A1 | 40:B7 01 | mov dil,1 |000000014014C1A4 | 48:85DB | test rbx,rbx |000000014014C1A7 | 74 08 | je gsexplorer.14014C1B1 |000000014014C1A9 | 48:8BCB | mov rcx,rbx | 000000014014C1AC | E8 2FEA1E00 | call gsexplorer.14033ABE0 | 注意 rsi 指针000000014014C1B1 | 40:0FB6C7 | movzx eax,dil |000000014014C1B5 | 48:8B8C24 9800000 | mov rcx,qword ptr ss:[rsp+98] |000000014014C1BD | 48:33CC | xor rcx,rsp |000000014014C1C0 | E8 DBFD1D00 | call gsexplorer.14032BFA0 |000000014014C1C5 | 48:81C4 A8000000 | add rsp,A8 |000000014014C1CC | 41:5F | pop r15 |000000014014C1CE | 41:5E | pop r14 |000000014014C1D0 | 41:5D | pop r13 |000000014014C1D2 | 41:5C | pop r12 | 000000014014C1D4 | 5F | pop rdi |000000014014C1D5 | 5E | pop rsi | 000000014014C1D6 | 5D | pop rbp |000000014014C1D7 | 5B | pop rbx |000000014014C1D8 | C3 | ret |[/ol]复制代码
加密流程
1. 根据被加密数据生成一个 `salt seek`
2. 根据 `salt seek` 生成 `salt`, 使用该盐值与密钥根据 `sha1` 生成 `key` 和 `iv`
3. 使用 AES 加密数据
4. 将 `salt seek` 追加到加密结果
5. 使用 `base64` 加密数组, 这部分 GoodSync 稍微改变了 Base64 Table
解密过程
观察到 gsdata 文件夹和压缩包 gs_zipfs_state
GS 会在解密前先使用加密算法计算加密后的文件名, 从远端拉取这个文件回本地解密
该文件内包含同步信息, 例如被加密的文件名
项目
剩下的部分想必对于 18+ cm 的 mjj 是很自然的
考虑到程序的易用性, 写了一个 python 包供 mjj 们调用
安装只需要
[ol]python -m pip install goodsync [/ol]复制代码
项目开源, 希望能得到 mjj 们的星星
https://github.com/bitjerry/goodsync
项目只实现了加解密, 更多功能欢迎 PR, 如果你有其它语言实现也欢迎 PR
|
|