逆向工程String.GetHashCode

Ken*_*enn 4 c# gethashcode

String.GetHashCode的行为取决于程序架构.因此它将在x86中返回一个值,在x64上返回一个值.我有一个必须在x86中运行的测试应用程序,它必须预测必须在x64上运行的应用程序的哈希码输出.

下面是mscorwks中String.GetHashCode实现的反汇编.

public override unsafe int GetHashCode()
{
      fixed (char* text1 = ((char*) this))
      {
            char* chPtr1 = text1;
            int num1 = 0x15051505;
            int num2 = num1;
            int* numPtr1 = (int*) chPtr1;
            for (int num3 = this.Length; num3 > 0; num3 -= 4)
            {
                  num1 = (((num1 << 5) + num1) + (num1 >? 0x1b)) ^ numPtr1[0];
                  if (num3 <= 2)
                  {
                        break;
                  }
                  num2 = (((num2 << 5) + num2) + (num2 >> 0x1b)) ^ numPtr1[1];
                  numPtr1 += 2;
            }
            return (num1 + (num2 * 0x5d588b65));
      }
}
Run Code Online (Sandbox Code Playgroud)

任何人都可以将此功能移植到安全的实现?

Jon*_*Jon 20

哈希代码不能跨平台重复,甚至不能在同一系统上多次运行同一程序.你走错了路.如果你不改变路线,那么你的道路将很艰难,有一天它可能会以泪水结束.

你想要解决的真正问题是什么?是否可以编写自己的哈希函数,作为扩展方法或作为GetHashCode包装类的实现并使用那个?


Eri*_*ert 16

首先,乔恩是正确的; 这是一个傻瓜的差事.我们用来"吃我们自己的dogfood"的框架的内部调试版本每天都会改变哈希算法,以防止人们构建系统 - 甚至是测试系统 - 依赖于不可靠的实现细节,这些细节被记录为可能会发生变化随时.

我的建议是退后一步,问问自己为什么要尝试做一些危险的事情,而不是将系统的仿真记录为不适合仿真的系统.这真的是一个要求吗?

其次,StackOverflow是一个技术问答网站,而不是"为我免费工作"网站.如果你一心想做这个危险的事情,你需要有人可以将不安全的代码重写成等效的安全代码,那么我建议你聘请能为你做这件事的人.

  • @Konstantin:我一点也不生气; 作为我的客户,我希望肯恩能够成功.因此,我坚定地认为:(1)这是一个可能会导致未来成本高昂的坏主意,(2)StackOverflow是一个讨论*事实*的好地方,也是一个不好的地方.*免费工作*.知道这一点的人更有可能成功使用StackOverflow. (4认同)

rea*_*520 5

虽然这里给出的所有警告都是有效的,但它们并没有回答这个问题。我遇到过这样的情况,不幸的是 GetHashCode() 已经被用于生产中的持久值,我别无选择,只能使用默认的 .NET 2.0 32 位 x86(小端)算法重新实现。我重新编码没有不安全,如下所示,这似乎有效。希望这可以帮助某人。

// The GetStringHashCode() extension method is equivalent to the Microsoft .NET Framework 2.0
// String.GetHashCode() method executed on 32 bit systems.
public static int GetStringHashCode(this string value)
{
    int hash1 = (5381 << 16) + 5381;
    int hash2 = hash1;

    int len = value.Length;
    int intval;
    int c0, c1;
    int i = 0;
    while (len > 0)
    {
        c0 = (int)value[i];
        c1 = len > 1 ? (int)value[i + 1] : 0;
        intval = c0 | (c1 << 16);
        hash1 = ((hash1 << 5) + hash1 + (hash1 >> 27)) ^ intval;
        if (len <= 2)
        {
            break;
        }
        i += 2;
        c0 = (int)value[i];
        c1 = len > 3 ? (int)value[i + 1] : 0;
        intval = c0 | (c1 << 16);
        hash2 = ((hash2 << 5) + hash2 + (hash2 >> 27)) ^ intval;
        len -= 4;
        i += 2;
    }

    return hash1 + (hash2 * 1566083941);
}
Run Code Online (Sandbox Code Playgroud)