KeygenMe - 我的输出有一个错误的字符

逆向工程 反编译
2021-07-07 07:50:19

我正在尝试进行逆向工程,并从 .NET 开始,尝试我在互联网上找到的各种 CrackMes 和 KeygenMes。到目前为止,我还没有真正挣扎过,但最新的这个让我发疯:

https://tuts4you.com/download.php?view.1894

VT 链接(如果需要):https : //www.virustotal.com/en/file/9bd07d7cbd053f6ad27792487679b18b2f72b589440d8ab81f9cdc4d84301178/analysis/1454947890/

使用 ILSpy 反编译显示执行的许可证检查:

    FileStream fileStream = new FileStream("key.dat", FileMode.Open, FileAccess.Read);
    StreamReader streamReader = new StreamReader(fileStream);
    string text = streamReader.ReadToEnd();
    byte[] bytes = Encoding.Unicode.GetBytes(this.TextBox1.Text);
    SHA512 sHA = new SHA512Managed();
    sHA.ComputeHash(bytes);
    if (Operators.ConditionalCompareObjectEqual(this.CodeCrypt(text), Convert.ToBase64String(sHA.Hash), true))
    {
        Interaction.MsgBox("Good job, make a keymaker", MsgBoxStyle.Information, "Done");
    }
    else
    {
        Interaction.MsgBox("Try again, it is very simple", MsgBoxStyle.Critical, "No ....");
    }
    streamReader.Close();
    fileStream.Close();

这是 CodeCrypt 方法:

Key = "AoRE";
public string CodeCrypt(string text)
{
    string text2 = "";
    int arg_0F_0 = 1;
    int num = Strings.Len(text);
    checked
    {
        for (int i = arg_0F_0; i <= num; i++)
        {
            int num2 = i % Strings.Len(this.Key);
            if (num2 == 0)
            {
                num2 = Strings.Len(this.Key);
            }
            text2 += Conversions.ToString(Strings.Chr(Strings.Asc(Strings.Mid(this.Key, num2, 1)) ^ Strings.Asc(Strings.Mid(text, i, 1)) - 6));
        }
        return text2;
    }
}

看起来很简单,所以我生成了自己的密钥生成方法:

    private static string Key(string name)
    {
        string key = "";

        SHA512 sHA = new SHA512Managed();
        string hash = Convert.ToBase64String(sHA.ComputeHash(Encoding.Unicode.GetBytes(name)));


        for (int i = 1; i <= hash.Length; i++)
        {
            int num2 = i % 4;
            if (num2 == 0)
            {
                num2 = 4;
            }
            var test = Convert.ToChar(("AoRE"[num2 - 1] ^ hash[i - 1]) + 6);
            key += test;
        }
        return key;

    }

然后我写了我的许可证:

 using (StreamWriter sw = new StreamWriter(File.Open("key.dat", FileMode.Create), Encoding.Unicode))
        sw.Write(Key("Tom"));

但它失败了。我设置了一个断点来查看 CodeCrypt() 和 SHA512 哈希的输出是什么,并看到了这个:

CodeCrypt:8dmVQYHqap7MbFngePjLSxvaC9 ķ VgaDiyR2p550IFO2kzGAuC9yWufBs5LZGbKeR / KAFGVTBb47z4sa686eBTA == SHA512:8dmVQYHqap7MbFngePjLSxvaC9 / VgaDiyR2p550IFO2kzGAuC9yWufBs5LZGbKeR / KAFGVTBb47z4sa686eBTA ==

这些输出中的第 27 个字符不同,我只是不明白为什么。我在这里错过了什么?

提前致谢。

1个回答

您的算法为 base64 编码散列的每个字符计算正确的字节,但是您对该字节的字符串编码的实现不正确。

Convert.ToChar() 简单地将字节转换为字符。

VBStrings.Chr()使用系统当前的默认代码页将字节转换为 unicode。这很可能是适用于美国/西欧的 Windows-1252。

对于 bytes 0x00-0x7F,UTF-8 和 Windows-1252 具有相同的二进制表示。但是字节 0x80-0xFF 的情况有所不同,而且恰好 / 字符是唯一一个 XOR 值大于 0x7F(它是 0x83)的字符。

在 Windows-1252 中,0x80-0xFF 表示单字节扩展字符。在 UTF-8 中,这些扩展字符需要两个字节的存储空间:0x01 0x92。

这意味着crackme 有问题,因为许可证文件取决于系统的字符编码(可能会更改)。许可证文件应始终使用 unicode。

要修复您的代码,请替换Convert.ToChar()Encoding.Default.GetString()

var test = Encoding.Default.GetString(
               new[] { (byte)(("AoRE"[num2 - 1] ^ hash[i - 1]) + 6) });

编辑添加

我想指出的一件事是 C# 中的 char 是 2 个字节并存储一个 16 位 unicode 字符(与 C 中的 char 是 1 个字节不同)。这就是为什么强制转换和使用默认编码是不同的操作。