【发布时间】:2015-07-31 18:40:42
【问题描述】:
在 .NET 4.5 中,此密码在 32 位和 64 位架构上完美运行。将项目切换到 .NET 4.6 会在 64 位中完全破解此密码,而在 32 位中,有一个 odd 补丁可以解决这个问题。
在我的方法“DecodeSkill”中,SkillLevel 是唯一在 .NET 4.6 上中断的部分。 此处使用的变量是从网络流中读取并进行编码的。
DecodeSkill(总是为 SkillLevel 返回正确的解码值)
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);
}
ExchangeShortBits
private static uint ExchangeShortBits(uint data, int bits)
{
data &= 0xffff;
return (data >> bits | data << (16 - bits)) & 65535;
}
DecodeSkill(Patched for .NET 4.6 32-bit,注意“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);
}
【问题讨论】:
-
你能举一个输入数据、好的输出和坏输出的例子吗?
-
好的,给我 2-3 分钟。
-
@Scotty 你能发一个sscce 来实际重现问题吗?有一些你可以实际编译的东西而不是分析这个伪代码会很有帮助。
-
C# 语言中的这些操作中没有未定义的行为。结果是精确定义的。不管它是什么,它应该总是一样的。这是我在 .NET 4.6 发布后听到的第三个 JIT 错误。请在 CoreCLR 项目的 GitHub 上报告。
-
调试模式,如果你使用var x = SkillLevel,值会正确。释放模式,您无法更正该值。但 Asad 提供了解决此问题的方法。
标签: c# .net-4.5 bit-shift xor .net-4.6