在.NET 4.5中,此加密算法在32位和64位架构上完美运行。将项目切换到.NET 4.6后,64位上完全破坏了此密码,而在32位上有一个奇怪的补丁来解决问题。
在我的方法“DecodeSkill”中,“SkillLevel是唯一在.NET 4.6上出现问题的部分。这里使用的变量从网络流中读取并进行编码。
DecodeSkill(始终返回适当解码的值)
private void DecodeSkill()
{
SkillId = (ushort) (ExchangeShortBits((SkillId ^ ObjectId ^ 0x915d), 13) + 0x14be);
SkillLevel = ((ushort) ((byte)SkillLevel ^ 0x21));
TargetObjectId = (ExchangeLongBits(TargetObjectId, 13) ^ ObjectId ^ 0x5f2d2463) + 0x8b90b51a;
PositionX = (ushort) (ExchangeShortBits((PositionX ^ ObjectId ^ 0x2ed6), 15) + 0xdd12);
PositionY = (ushort) (ExchangeShortBits((PositionY ^ ObjectId ^ 0xb99b), 11) + 0x76de);
}
交换短位
private static uint ExchangeShortBits(uint data, int bits)
{
data &= 0xffff;
return (data >> bits | data << (16 - bits)) & 65535;
}
DecodeSkill (.NET 4.6 32位版已打补丁,注意“var patch = SkillLevel”)
private void DecodeSkill()
{
SkillId = (ushort) (ExchangeShortBits((SkillId ^ ObjectId ^ 0x915d), 13) + 0x14be);
var patch = SkillLevel = ((ushort) ((byte)SkillLevel ^ 0x21));
TargetObjectId = (ExchangeLongBits(TargetObjectId, 13) ^ ObjectId ^ 0x5f2d2463) + 0x8b90b51a;
PositionX = (ushort) (ExchangeShortBits((PositionX ^ ObjectId ^ 0x2ed6), 15) + 0xdd12);
PositionY = (ushort) (ExchangeShortBits((PositionY ^ ObjectId ^ 0xb99b), 11) + 0x76de);
}
将变量命名为SkillLevel,并且仅在32位模式下,将会导致SkillLevel始终是正确的值。如果删除此修补程序,则该值将始终不正确。在64位模式下,即使使用修补程序,此值也始终不正确。
我尝试在解码方法上使用MethodImplOptions.NoOptimization和MethodImplOptions.NoInlining,以期望获得改进。
有什么想法会引起这种情况吗?
编辑:我被要求提供输入、良好输出和错误输出的示例。 这来自一个实际的使用场景,值由客户端发送,并使用.NET 4.6上的“修补程序”正确解码。
输入:
ObjectId = 1000001
TargetObjectId = 2778236265
PositionX = 32409
PositionY = 16267
SkillId = 28399
SkillLevel = 8481
良好的输出
TargetObjectId = 0
PositionX = 302
PositionY = 278
SkillId = 1115
SkillLevel = 0
输出错误
TargetObjectId = 0
PositionX = 302
PositionY = 278
SkillId = 1115
SkillLevel = 34545
编辑#2:
我应该包含这一部分,这绝对是其中一个重要的部分。
EncodeSkill(时间戳为Environment.TickCount)
private void EncodeSkill()
{
SkillId = (ushort) (ExchangeShortBits(ObjectId - 0x14be, 3) ^ ObjectId ^ 0x915d);
SkillLevel = (ushort) ((SkillLevel + 0x100*(Timestamp%0x100)) ^ 0x3721);
Arg1 = MathUtils.BitFold32(SkillId, SkillLevel);
TargetObjectId = ExchangeLongBits(((TargetObjectId - 0x8b90b51a) ^ ObjectId ^ 0x5f2d2463u), 19);
PositionX = (ushort) (ExchangeShortBits((uint) PositionX - 0xdd12, 1) ^ ObjectId ^ 0x2ed6);
PositionY = (ushort) (ExchangeShortBits((uint) PositionY - 0x76de, 5) ^ ObjectId ^ 0xb99b);
}
BitFold32
public static int BitFold32(int lower16, int higher16)
{
return (lower16) | (higher16 << 16);
}
交换长整型位
private static uint ExchangeLongBits(uint data, int bits)
{
return data >> bits | data << (32 - bits);
}