需要帮助理解复杂的数学密码检查功能吗?

逆向工程 部件 数学
2021-06-16 00:30:11

下面是一个数学问题的复杂伪代码,它试图检查输入的密码是否正确。

Previous Analysis Done:数据以3x3矩阵的形式排列,i,j为行,列,k为临时变量,生成测试条件。元素 v6、v7、v8 .. 等在 k 循环中用作数组。最终目标是返回 0 以成功完成代码。

signed __int64 __fastcall check_password(const char *a1)
{
  signed int i; // [rsp+10h] [rbp-30h]
  signed int j; // [rsp+14h] [rbp-2Ch]
  int v4; // [rsp+18h] [rbp-28h]
  signed int k; // [rsp+1Ch] [rbp-24h]
  char v6; // [rsp+20h] [rbp-20h]
  char v7; // [rsp+21h] [rbp-1Fh]
  char v8; // [rsp+22h] [rbp-1Eh]
  char v9; // [rsp+23h] [rbp-1Dh]
  char v10; // [rsp+24h] [rbp-1Ch]
  char v11; // [rsp+25h] [rbp-1Bh]
  char v12; // [rsp+26h] [rbp-1Ah]
  char v13; // [rsp+27h] [rbp-19h]
  char v14; // [rsp+28h] [rbp-18h]
  unsigned __int64 v15; // [rsp+38h] [rbp-8h]

  v15 = __readfsqword(0x28u);
  v6 = 79; 
  v7 = 8;
  v8 = 29;
  v9 = 58;
  v10 = 81;
  v11 = 21;
  v12 = 49;
  v13 = 123;
  v14 = 114;
  if ( strlen(a1) != 9 )
    return -1;
  for ( i = 0; i <= 2; ++i )
  {
    for ( j = 0; j <= 2; ++j )
    {
      v4 = 0;
      for ( k = 0; k <= 2; ++k )
        v4 = (a1[3 * k + j] * *(&v6 + 3 * i + k) + v4) % 127;
      if ( i == j )
      {
        if ( v4 != 1 )
          return -2;
      }
      else if ( v4 )
      {
        return -2;
      }
    }
  }
  return 0;
}
1个回答

由于您已经对代码进行了大部分解码,因此还剩下两件事:1) 了解代码在做什么,以及 2) 了解如何计算适当的输入。

原始代码

首先,这是根据您已有的代码稍作修改的代码:

int check_password(const char *s) {
    char fixed[] __attribute__ ((aligned (16))) = { 79, 8, 29, 58, 81, 21, 49, 123, 114 };
    if (strlen(s) != 9)
        return -1;
    for (int i=0; i < 3; ++i) {
        for (int j=0; j < 3; ++j) {
            int sum = 0;
            for (int k=0; k < 3; ++k) {
                sum = (fixed[3 * i + k] * s[3 * k + j] + sum) % 127;
            }
            if (i == j) {
                if (sum != 1) {
                    return -2;
                }
            } else if (sum) {
                return -2;
            }
        }
    }
    return 0;
}

__attribute__ ((aligned (16)))出于我们的目的可以忽略。(我已将其包含在内,以便gcc使用与示例代码相同的堆栈偏移量。)代码所做的是将两个 3x3 矩阵相乘,取模 127,并检查单位矩阵。

数学

不幸的是,ReverseEngineering 不支持 MathJax,否则我可以写出漂亮的方程式。既然我做不到,我们就硬着头皮去做。假设s = "ABCDEFGHI"是输入密码,我们将其视为 3x3 矩阵。现在,如果我们只为密码中的每个字母分配大写字母,表示为一个矩阵,这是:

A B C        79   8  29       1 0 0
D E F   x    58  81  21   =   0 1 0    (mod 127)
G H I        49 123 114       0 0 1

如果你熟悉矩阵运算已经,你可能已经意识到,这意味着s必须是了的fixed矩阵。有多种计算方法,例如通过Gauss-Jordan 消元法另一种方法是将矩阵行列式的倒数乘以辅因子矩阵的转置请注意,所有数学运算都是按照原始代码在 mod 127 中完成的。

工作实例

为了让事情更具体一点,我将使用后一种方法并展示逐步解决的解决方案。首先,我们使用莱布尼茨公式计算行列式

D = 79*81*114 + 8*21*49 + 29*58*123 - 29*81*49 - 8*58*114 - 79*21*123   (mod 127)
D = 572550 (mod 127)
D = 34  (mod 127)

为了计算倒数,我们不能仅仅使用它,1/34因为我们正在使用模块化数学。因此,正如我们所期望的那样,34 * 1/34 = 1对于常规数学,在模块化数学中,我们正在寻找满足方程的东西34 * x = 1 (mod 127)一种方法是使用扩展的欧几里得算法我不会在这里讨论那个算法,但在这种情况下,答案是 71(我们可以通过注意到71 * 34 = 2414 = 1 (mod 127).

接下来我们计算辅因子矩阵。同样,我们不会完成所有步骤,但 的辅因子矩阵fixed是:

 6651  -5583   3165
 2655   7585  -9325     (mod 127) 
-2181     23   5935

由于我们正在使用模块化数学,我们可以减少这种情况:

 47     5   117
115    92    73      (mod 127)
105    23    93

现在剩下的就是将它们相乘:

         47     5   117
71   *  115    92    73      (mod 127)
        105    23    93


3337    355   8307
8165   6532   5183   (mod 127) 
7455   1633   6603

35   101    52
37    55   103    (mod 127)
89   109   126

最后,我们进行转置:

 35    37    89
101    55   109
 52   103   126

如果我们然后将此矩阵转换回 ASCII 字符串,我们将得到"#%Ye7m4g~"给定矩阵的逆矩阵以及该逆向工程问题的解决方案。

为什么这可能很重要

虽然它本身可能是一个足够有趣的谜题,但这些使用离散数学和模算术的转换是现代密码学许多领域的基础。由于您已经开始研究逆向工程,您可能会发现研究这些主题也很有用且很有趣。