【问题标题】:32bit Reverse Engineered Encryption Function Failing 64bit32bit 逆向工程加密功能失败 64bit
【发布时间】:2012-01-14 15:14:32
【问题描述】:
signed int _rotr( int a1, int a2 )
{
    return (a1 << a2 % 0x20u) | ((unsigned int)a1 >> (char)(32 - a2 % 0x20u));
}
int _encrypt_password( int a1, int a2, signed int a3 )
{
    signed int  v10; // [sp+10h] [bp-8h]@3
    int         result; // eax@1
    int         v4; // ebx@3
    int         v5; // edi@3
    int         v6; // esi@3
    int         v7; // eax@4
    int         v8; // [sp+14h] [bp-4h]@2
    int         v9; // [sp+Ch] [bp-Ch]@2

    result = 8 * a3 / 8;
    a3 = 8 * a3 / 8;
    if ( result > 0 )
    {
        result = a2;
        v8 = 0;
        v9 = a2;
        while ( a3 / 8 > v8 )
        {
            v4 = *(_DWORD *)v9 + *(_DWORD *)(a1 + 16);
            v6 = *(_DWORD *)(v9 + 4) + *(_DWORD *)(a1 + 20);
            v10 = 1;
            v5 = a1 + 24;
            do
            {
                v7 = *(_DWORD *)v5 + _rotr(v6 ^ v4, v6);
                v4 = v7;
                v6 = *(_DWORD *)(v5 + 4) + _rotr(v7 ^ v6, v7);
                ++v10;
                v5 += 8;
            }
            while ( v10 <= 12 );
            result = v9;
            *(_DWORD *)v9 = v4;
            *(_DWORD *)(v9 + 4) = v6;
            ++v8;
            v9 += 8;
        }
    }
    return result;
}

以上是一组反向工程函数,它提供字符串(密码)的加密,用于向游戏服务器验证游戏客户端。原始加密不再可用,为此目的对其进行了反向工程。

代码在 32 位中完美运行,但是,在为 64 位系统编译时,我遇到了一些问题。该代码像在 32 位中一样成功构建,但是在执行该函数时,它会在遇到第一个 v4 分配行时出现段错误 (EXC_BAD_ACCESS):

v4 = *(_DWORD *)v9 + *(_DWORD *)(a1 + 16);

我试图了解该功能并弄清楚它实际提供的加密类型,但是我在这方面失败了。起初我使用 RC5 运行,但这导致了大约 2 天的数学运算,最终证明这对我的密码学技能非常有价值,但对手头的问题却是徒劳的。

我想知道关于这段代码的一件事或两件事:

首先也是最简单的,有没有人认出这是使用的算法或加密方法?它甚至使用标准方法吗?在我看来,它在某种程度上看起来像 RC5/ROT13/DES/AES,但我不知道。

其次,是否有任何迹象表明为什么这无法在 64 位中工作?

** 抱歉,_DWORD 是无符号长整数。

【问题讨论】:

  • 您将整数转换为指针,理论上 64 位程序使用 64 位指针,因此使用 (void*) 代替 int 存储指针可能会更好
  • 哈哈。是的,我认为它不是 rot13。老实说,我什至不认为它真正遵循任何直接加密方案。 _DWORD 定义为无符号长整数。 (void *) 在这种情况下不会编译,至少不会以它存在的形式编译。我尝试使用 uint64_t 和其他一些类型,但段错误仍然存​​在。
  • 就个人而言,我不会将您从 IDA 的伪代码窗口中盲目复制的内容称为“逆向工程函数集”...

标签: c++ security cryptography segmentation-fault reverse-engineering


【解决方案1】:

a1 和 a2 不是整数,它们是指针,同样,它们没有符号,它们是无符号的。在 64 位系统上,这些指针可能指向高于 max(int32) 的值,您可以尝试将它们转换为 64 位大小的值,例如 uint64_t。

【讨论】:

  • 这样做会导致相同的段错误...包括将每个 int 完全更改为 uint64_t。
【解决方案2】:

尝试用int32_t 替换所有出现的int 和_DWORD(你会想要#include &lt;stdint.h&gt;。你说_DWORD 被定义为unsigned long,这在许多32 位机器上将是一个32 位数量,但在 64 位机器上通常是 64。

或者,如果函数实际上是使用地址作为其参数调用的,看起来可能是这样,您可能想尝试在任何地方使用int64_t。您是否有一个如何调用函数的示例,以及 64 位系统上的一些示例输入?

【讨论】:

  • 该函数与一个 120 字节的 unsigned char 密钥和一个用于加密密码的缓冲 char 相关联:unsigned char buffer[] = { 0x00, 0x5D, 0x1E, 0xEE, 0xFF, 0xFF, 0xFF, 0xFF, 0xE4, 0x55, 0xA5, 0x71, 0x00, 0x00, 0x00, 0x00 }; 我说是缓冲的,因为它是用一个可能更小的字符串的 memcpy 修改的,它留下了尾随那里的信息作为身份验证机制的要求。函数调用是:_encrypt_password( (int)rc5_cipher, (int)buffer, 16 );我试试你说的,一会儿报告。
  • 尝试在valgrind 下运行,看看它认为无效访问是什么。另外,rc5_cipher 是什么?
  • rc5_cipher 是:unsigned char rc5_cipher[] = { 0xBC, 0x54, 0xE8, 0xEB, 0xF7, 0x98, 0x49, 0xB0, 0x8C, 0xA8, 0xFA, 0xFF, 0xBB, 0x54, 0xE8, 0x96, 0x56, 0x55, 0x91, 0xA9, 0x10, 0x41, 0xE4, 0x48, 0x8F, 0x30, 0x32, 0x9F, 0x3E, 0x1D, 0xF4, 0x27...(持续时间超过评论允许的时间)总共 120 个字节。
  • 好的,所以它实际上是一个数组,所以降级为一个指针,所以你的函数的第一个参数应该是 void* 或 unsigned char* 类型。我希望你能从那里弄清楚其他类型需要什么,然后再试一次。我猜测指向 rc5_cipher 的 64 位指针在 64 位系统上被截断,因为该函数是通过将指针转换为 int 来调用的,这不是真的。
  • 好的,所以在与您的方向相关的一些更改之后,我实际上想通了。尽管最终的解决方案实际上是将 unsigned char 转换为 int,但我需要做一些事情。我将_DWORD修改为uint64_t,并将所有指针也更改为相同。
猜你喜欢
  • 1970-01-01
  • 2012-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-22
  • 1970-01-01
  • 1970-01-01
  • 2010-11-12
相关资源
最近更新 更多