Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions TACTLib/Core/Product/Tank/CMF/ProCMF_154504.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
using static TACTLib.Core.Product.Tank.ManifestCryptoHandler;
using static TACTLib.Core.Product.Tank.ContentManifestFile;

namespace TACTLib.Core.Product.Tank.CMF
{
// 154504 (Overwatch 2.25.0.1) -- 客户端真实算法,逆向自 Overwatch.exe
// Key 生成 RVA 0x34622A0, IV 生成 RVA 0x3461EA0 (CMF 读取包装 RVA 0x24CA550)
// Keytable = Overwatch.exe .rdata RVA 0x48034C0 (明文常量 512 字节)
// 注意: 与 ProCMF_154088 等旧类的公式不同, 旧公式对本表无效.
//
// 覆盖范围(已实测): 主清单 Win_SPWin_RCN_EExt.cmf 与
// Win_SPWin_RCN_LzhCN_text_EExt.cmf / _LzhCN_speech_EExt.cmf
// **共用这一张表 + 这一套公式**, 不存在"语言清单专用第二张表".
// 语言清单的差别只在 header.m_entryCount == 0 (只有 hash 列表, 无 entry 索引),
// 因此 IV 里的 count 项走的是 m_dataCount 分支, 公式本身不变.
[ManifestCrypto(AutoDetectVersion = true, Product = TACTProduct.Overwatch)]
public class ProCMF_154504 : ICMFEncryptionProc
{
public byte[] Key(CMFHeader header, int length)
{
byte[] buffer = new byte[length];
uint kidx = Keytable[0x100 + length];
for (int i = 0; i != length; ++i)
{
buffer[i] = Keytable[SignedMod(kidx, 512)];
kidx += 3;
}
return buffer;
}

public byte[] IV(CMFHeader header, byte[] digest, int length)
{
byte[] buffer = new byte[length];
uint kidx = (uint)(length * header.m_buildVersion);
uint step = (uint)(header.m_dataCount + digest[header.m_dataCount % 20]);
for (int i = 0; i != length; ++i)
{
buffer[i] = Keytable[SignedMod(kidx, 512)];
kidx += step;
buffer[i] ^= digest[SignedMod(header.m_buildVersion + i, SHA1_DIGESTSIZE)];
}
return buffer;
}

private static readonly byte[] Keytable =
{
0x02, 0x62, 0x30, 0x3A, 0xD7, 0x04, 0x18, 0x6B, 0x0B, 0x2D, 0x04, 0x52, 0x25, 0xDF, 0xA1, 0xBC,
0x0E, 0x6F, 0xCE, 0x3C, 0x8B, 0x53, 0x00, 0xE9, 0xF0, 0xF0, 0xD3, 0x59, 0x92, 0x58, 0x6E, 0xDB,
0x64, 0x6A, 0x88, 0xFF, 0xE2, 0x73, 0xD9, 0x92, 0x84, 0xB3, 0x97, 0xC7, 0x14, 0x72, 0xC3, 0xA2,
0xF7, 0x86, 0x00, 0xB8, 0x34, 0x20, 0xF3, 0x72, 0x85, 0x95, 0x2F, 0xD6, 0x6F, 0x0A, 0x9E, 0x6A,
0xB1, 0xD4, 0x9E, 0x27, 0xD4, 0x2C, 0xB3, 0x5A, 0x2A, 0xD9, 0x6E, 0x13, 0xE1, 0xC8, 0xBD, 0x69,
0x27, 0xBE, 0xC8, 0xF0, 0x7C, 0x49, 0xF0, 0x1C, 0xBA, 0x71, 0x4E, 0xEC, 0xAF, 0xFD, 0x06, 0x60,
0xEF, 0xA1, 0xFC, 0xBE, 0x48, 0x13, 0x03, 0xCB, 0x36, 0x62, 0xF4, 0x3F, 0x92, 0x83, 0xCB, 0x94,
0x7D, 0x50, 0x6C, 0xB1, 0xF2, 0xF0, 0xD6, 0x25, 0x2E, 0x1B, 0xDE, 0x1C, 0x59, 0xA2, 0x14, 0x58,
0x50, 0x1A, 0x22, 0x27, 0xD1, 0x81, 0x5C, 0x21, 0x72, 0x6F, 0x59, 0xC7, 0xC6, 0x77, 0x92, 0x9F,
0xF8, 0x2F, 0x8A, 0x91, 0xF0, 0xA3, 0x8A, 0x9A, 0xE0, 0x43, 0x1A, 0x90, 0x73, 0x05, 0x61, 0xF4,
0x1A, 0x03, 0x74, 0x40, 0xF9, 0x8C, 0x3B, 0xEA, 0xD9, 0x2A, 0x85, 0x7A, 0x34, 0x73, 0x5C, 0x3A,
0x02, 0x4A, 0x7C, 0xC2, 0x34, 0xFB, 0x63, 0xD6, 0x64, 0xC2, 0xD9, 0x33, 0x7B, 0x62, 0xA6, 0xA6,
0x7E, 0x7B, 0xA1, 0x7E, 0x59, 0x2A, 0xA2, 0x79, 0x5A, 0x16, 0xB7, 0xFA, 0xCF, 0x26, 0xAC, 0x72,
0x78, 0x5B, 0xF5, 0x21, 0xD7, 0xCF, 0xDB, 0xEA, 0x9E, 0x71, 0xBD, 0xA9, 0xB5, 0x3C, 0x46, 0x4A,
0xAF, 0xFA, 0xE3, 0x9D, 0x3B, 0x6A, 0x14, 0x58, 0xD0, 0x98, 0xE8, 0x45, 0xF4, 0x53, 0x5A, 0x94,
0xC0, 0x86, 0x39, 0xBE, 0x96, 0x40, 0x89, 0x82, 0x47, 0x61, 0x65, 0xCC, 0x27, 0x9F, 0xE0, 0xDC,
0x7D, 0x5A, 0xDC, 0xCF, 0x2E, 0x89, 0x5B, 0x01, 0xCE, 0x18, 0x81, 0x8F, 0x68, 0x8C, 0xD3, 0x4A,
0x5D, 0xA3, 0x8E, 0xC5, 0xA2, 0x94, 0xB3, 0x9F, 0x6A, 0x9F, 0x15, 0x68, 0x52, 0x60, 0xF3, 0x07,
0x19, 0x0C, 0x1F, 0x42, 0xC9, 0x20, 0x5F, 0x5D, 0xD5, 0x05, 0xA8, 0xA9, 0xAA, 0xE7, 0xFC, 0x61,
0x24, 0x75, 0x82, 0x70, 0x1F, 0x84, 0x80, 0x2D, 0x27, 0xAE, 0x34, 0x81, 0x6A, 0xD1, 0x71, 0xD1,
0xF4, 0xB0, 0x19, 0x2F, 0xBD, 0x3C, 0x06, 0x25, 0xC1, 0x75, 0xDC, 0xFB, 0x31, 0xA5, 0xB4, 0x47,
0x85, 0x03, 0x09, 0x69, 0x55, 0x2C, 0x89, 0xFC, 0xBA, 0xF6, 0x80, 0x95, 0xDB, 0x68, 0x0E, 0x5C,
0x19, 0x76, 0x43, 0x94, 0x29, 0x8A, 0xFD, 0xE0, 0x82, 0x4E, 0xAC, 0x57, 0x53, 0xE5, 0x3B, 0xD5,
0x5A, 0x2D, 0xAB, 0x00, 0x89, 0xE3, 0x49, 0xF6, 0xB7, 0xD3, 0xCB, 0x7D, 0x43, 0x37, 0xEB, 0xC5,
0x7B, 0xB9, 0x18, 0xC6, 0x54, 0xEE, 0x47, 0x3F, 0xCB, 0x42, 0x66, 0x39, 0x01, 0x97, 0xD3, 0x74,
0x36, 0xE0, 0xFB, 0x6F, 0xB3, 0x6D, 0x69, 0x27, 0xC9, 0xFC, 0x0E, 0x4E, 0x28, 0x51, 0x80, 0xDD,
0xE2, 0x2C, 0x50, 0x59, 0x10, 0x1A, 0xFE, 0x3B, 0x63, 0xB0, 0x49, 0x5E, 0x27, 0x1D, 0x11, 0x50,
0x2F, 0x5B, 0xC9, 0x07, 0xA2, 0xBB, 0x9E, 0x0A, 0x30, 0x7F, 0x1A, 0x5C, 0xAB, 0x54, 0x39, 0x81,
0xB9, 0x20, 0x10, 0x72, 0xD7, 0x73, 0x15, 0x76, 0xA1, 0x34, 0xA1, 0x1F, 0x55, 0x21, 0x14, 0x8D,
0x4E, 0xDE, 0xFE, 0x9B, 0x08, 0x83, 0x35, 0x21, 0x94, 0x4F, 0xA5, 0x25, 0xC9, 0x0E, 0x52, 0x7C,
0xA9, 0x68, 0x7A, 0x60, 0xEC, 0xF1, 0x0D, 0x56, 0x87, 0x76, 0x34, 0xE8, 0xE5, 0xB2, 0x06, 0xE0,
0xB1, 0xFE, 0x3E, 0x37, 0x00, 0x69, 0xCE, 0xE5, 0x95, 0xB6, 0x94, 0xE7, 0x6C, 0x21, 0x7C, 0xC7,
};
}
}
78 changes: 78 additions & 0 deletions TACTLib/Core/Product/Tank/TRG/ProTRG_154504.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
using static TACTLib.Core.Product.Tank.ManifestCryptoHandler;
using static TACTLib.Core.Product.Tank.ResourceGraph;

namespace TACTLib.Core.Product.Tank.TRG
{
// 154504 (Overwatch 2.25.0.1) -- 客户端真实算法
// Keytable 与 CMF 154504 共用同一张 512 字节表 (Overwatch.exe .rdata RVA 0x48034C0)
// 加密流与 CMF 相同: AES-256-CBC, 整段 body 一条流; 尾部 12 字节 0x0C 填充已验证
// Key: kidx = T[0x100 + length]; key[i] = T[kidx % 512]; kidx += 3
// IV : kidx = (16 * build) % 512; step = (packageCount + SHA1(name)[packageCount % 20]) % 512
// iv[i] = T[kidx % 512] ^ SHA1(name)[(build + i) % 20]; kidx += step
// 注意: 与 ProTRG_154088 的公式完全不同(旧公式在本版本上得不出正确 key).
[ManifestCrypto(AutoDetectVersion = true, Product = TACTProduct.Overwatch)]
public class ProTRG_154504 : ITRGEncryptionProc
{
public byte[] Key(TRGHeader header, int length)
{
byte[] buffer = new byte[length];
uint kidx = Keytable[0x100 + length];
for (int i = 0; i != length; ++i)
{
buffer[i] = Keytable[SignedMod(kidx, 512)];
kidx += 3;
}
return buffer;
}

public byte[] IV(TRGHeader header, byte[] digest, int length)
{
byte[] buffer = new byte[length];
uint kidx = (uint)(length * header.m_buildVersion);
uint step = (uint)(header.m_packageCount + digest[header.m_packageCount % SHA1_DIGESTSIZE]);
for (int i = 0; i != length; ++i)
{
buffer[i] = Keytable[SignedMod(kidx, 512)];
kidx += step;
buffer[i] ^= digest[SignedMod(header.m_buildVersion + i, SHA1_DIGESTSIZE)];
}
return buffer;
}

private static readonly byte[] Keytable =
{
0x02, 0x62, 0x30, 0x3A, 0xD7, 0x04, 0x18, 0x6B, 0x0B, 0x2D, 0x04, 0x52, 0x25, 0xDF, 0xA1, 0xBC,
0x0E, 0x6F, 0xCE, 0x3C, 0x8B, 0x53, 0x00, 0xE9, 0xF0, 0xF0, 0xD3, 0x59, 0x92, 0x58, 0x6E, 0xDB,
0x64, 0x6A, 0x88, 0xFF, 0xE2, 0x73, 0xD9, 0x92, 0x84, 0xB3, 0x97, 0xC7, 0x14, 0x72, 0xC3, 0xA2,
0xF7, 0x86, 0x00, 0xB8, 0x34, 0x20, 0xF3, 0x72, 0x85, 0x95, 0x2F, 0xD6, 0x6F, 0x0A, 0x9E, 0x6A,
0xB1, 0xD4, 0x9E, 0x27, 0xD4, 0x2C, 0xB3, 0x5A, 0x2A, 0xD9, 0x6E, 0x13, 0xE1, 0xC8, 0xBD, 0x69,
0x27, 0xBE, 0xC8, 0xF0, 0x7C, 0x49, 0xF0, 0x1C, 0xBA, 0x71, 0x4E, 0xEC, 0xAF, 0xFD, 0x06, 0x60,
0xEF, 0xA1, 0xFC, 0xBE, 0x48, 0x13, 0x03, 0xCB, 0x36, 0x62, 0xF4, 0x3F, 0x92, 0x83, 0xCB, 0x94,
0x7D, 0x50, 0x6C, 0xB1, 0xF2, 0xF0, 0xD6, 0x25, 0x2E, 0x1B, 0xDE, 0x1C, 0x59, 0xA2, 0x14, 0x58,
0x50, 0x1A, 0x22, 0x27, 0xD1, 0x81, 0x5C, 0x21, 0x72, 0x6F, 0x59, 0xC7, 0xC6, 0x77, 0x92, 0x9F,
0xF8, 0x2F, 0x8A, 0x91, 0xF0, 0xA3, 0x8A, 0x9A, 0xE0, 0x43, 0x1A, 0x90, 0x73, 0x05, 0x61, 0xF4,
0x1A, 0x03, 0x74, 0x40, 0xF9, 0x8C, 0x3B, 0xEA, 0xD9, 0x2A, 0x85, 0x7A, 0x34, 0x73, 0x5C, 0x3A,
0x02, 0x4A, 0x7C, 0xC2, 0x34, 0xFB, 0x63, 0xD6, 0x64, 0xC2, 0xD9, 0x33, 0x7B, 0x62, 0xA6, 0xA6,
0x7E, 0x7B, 0xA1, 0x7E, 0x59, 0x2A, 0xA2, 0x79, 0x5A, 0x16, 0xB7, 0xFA, 0xCF, 0x26, 0xAC, 0x72,
0x78, 0x5B, 0xF5, 0x21, 0xD7, 0xCF, 0xDB, 0xEA, 0x9E, 0x71, 0xBD, 0xA9, 0xB5, 0x3C, 0x46, 0x4A,
0xAF, 0xFA, 0xE3, 0x9D, 0x3B, 0x6A, 0x14, 0x58, 0xD0, 0x98, 0xE8, 0x45, 0xF4, 0x53, 0x5A, 0x94,
0xC0, 0x86, 0x39, 0xBE, 0x96, 0x40, 0x89, 0x82, 0x47, 0x61, 0x65, 0xCC, 0x27, 0x9F, 0xE0, 0xDC,
0x7D, 0x5A, 0xDC, 0xCF, 0x2E, 0x89, 0x5B, 0x01, 0xCE, 0x18, 0x81, 0x8F, 0x68, 0x8C, 0xD3, 0x4A,
0x5D, 0xA3, 0x8E, 0xC5, 0xA2, 0x94, 0xB3, 0x9F, 0x6A, 0x9F, 0x15, 0x68, 0x52, 0x60, 0xF3, 0x07,
0x19, 0x0C, 0x1F, 0x42, 0xC9, 0x20, 0x5F, 0x5D, 0xD5, 0x05, 0xA8, 0xA9, 0xAA, 0xE7, 0xFC, 0x61,
0x24, 0x75, 0x82, 0x70, 0x1F, 0x84, 0x80, 0x2D, 0x27, 0xAE, 0x34, 0x81, 0x6A, 0xD1, 0x71, 0xD1,
0xF4, 0xB0, 0x19, 0x2F, 0xBD, 0x3C, 0x06, 0x25, 0xC1, 0x75, 0xDC, 0xFB, 0x31, 0xA5, 0xB4, 0x47,
0x85, 0x03, 0x09, 0x69, 0x55, 0x2C, 0x89, 0xFC, 0xBA, 0xF6, 0x80, 0x95, 0xDB, 0x68, 0x0E, 0x5C,
0x19, 0x76, 0x43, 0x94, 0x29, 0x8A, 0xFD, 0xE0, 0x82, 0x4E, 0xAC, 0x57, 0x53, 0xE5, 0x3B, 0xD5,
0x5A, 0x2D, 0xAB, 0x00, 0x89, 0xE3, 0x49, 0xF6, 0xB7, 0xD3, 0xCB, 0x7D, 0x43, 0x37, 0xEB, 0xC5,
0x7B, 0xB9, 0x18, 0xC6, 0x54, 0xEE, 0x47, 0x3F, 0xCB, 0x42, 0x66, 0x39, 0x01, 0x97, 0xD3, 0x74,
0x36, 0xE0, 0xFB, 0x6F, 0xB3, 0x6D, 0x69, 0x27, 0xC9, 0xFC, 0x0E, 0x4E, 0x28, 0x51, 0x80, 0xDD,
0xE2, 0x2C, 0x50, 0x59, 0x10, 0x1A, 0xFE, 0x3B, 0x63, 0xB0, 0x49, 0x5E, 0x27, 0x1D, 0x11, 0x50,
0x2F, 0x5B, 0xC9, 0x07, 0xA2, 0xBB, 0x9E, 0x0A, 0x30, 0x7F, 0x1A, 0x5C, 0xAB, 0x54, 0x39, 0x81,
0xB9, 0x20, 0x10, 0x72, 0xD7, 0x73, 0x15, 0x76, 0xA1, 0x34, 0xA1, 0x1F, 0x55, 0x21, 0x14, 0x8D,
0x4E, 0xDE, 0xFE, 0x9B, 0x08, 0x83, 0x35, 0x21, 0x94, 0x4F, 0xA5, 0x25, 0xC9, 0x0E, 0x52, 0x7C,
0xA9, 0x68, 0x7A, 0x60, 0xEC, 0xF1, 0x0D, 0x56, 0x87, 0x76, 0x34, 0xE8, 0xE5, 0xB2, 0x06, 0xE0,
0xB1, 0xFE, 0x3E, 0x37, 0x00, 0x69, 0xCE, 0xE5, 0x95, 0xB6, 0x94, 0xE7, 0x6C, 0x21, 0x7C, 0xC7
};
}
}