【问题标题】:Reverse Engineering - What's Kind of Algorithm In This Code?逆向工程 - 此代码中的算法类型是什么?
【发布时间】:2021-03-10 14:54:23
【问题描述】:

谁能帮我看看这是什么类型的算法?

public class hf1 {

    public static final String[] f3650a = {"0sFU@W>Ao*BT64?[L5aONSK.'"...};

    public static final String[] f3651b = {" \bB\u0017\u001e)YBN\u001eT/\u001e4V\u0001ZT/6VV"...};

    public static final String[] f3652c = {"\u0000\u0000\u0013\u00006\u0000\\\u0000\u0000¢\u0000¹\u0000¿\u0000"...};

    public static String m5192a(int i) {
        int i2 = i / 4096;
        int i3 = i % 4096;
        int i4 = i + 1;
        int i5 = i4 / 4096;
        int i6 = i4 % 4096;
        String[] strArr = f3652c;
        String str = strArr[i2];
        String str2 = strArr[i5];

        int i7 = i3 * 2;
        int charAt = ((str.charAt(i7 + 1) & 65535) << 16) | (str.charAt(i7) & 65535);
        int i8 = i6 * 2;
        int charAt2 = ((str2.charAt(i8 + 1) << 16) | str2.charAt(i8)) - charAt;
        char[] cArr = new char[charAt2];
        for (int i9 = 0; i9 < charAt2; i9++) {
            int i10 = charAt + i9;
            int charAt3 = f3651b[i10 / 8192].charAt(i10 % 8192) & 65535;
            cArr[i9] = f3650a[charAt3 / 8192].charAt(charAt3 % 8192);
        }
        return new String(cArr);
    }

}

如果我调用 m5192a(1) 并将任何 int 索引作为参数传递,代码将返回一个字符串。这就像在源代码中隐藏了某种纯字符串。

有人知道可能的反向代码吗?将纯字符串转换为此?这是一种有名字的已知技术吗?

【问题讨论】:

  • hash function 通常将字符串转换为数字。这与你所拥有的相反,但也许它可以以某种方式帮助你......
  • 这看起来像是一种算法,可以确定性地生成从 int 键看起来随机的字符串。您可能会问这个关于明显反编译代码的问题的一个原因是试图从当前服务(您只有已编译的 Java)计算服务的未来密钥,以便您可以做一些邪恶的事情。您需要证明非恶意意图。 IE。你不是想众包一个黑客。
  • 我投票结束这个问题,因为它似乎是众包某种邪恶的活动。

标签: java algorithm obfuscation


【解决方案1】:

我不确定“有名字的已知技术”——也许像“反函数”或“双向化”这样的关键字可能会有所帮助,例如In pure functional languages, is there an algorithm to get the inverse function?

对于这个特定的函数,幸运的是,只要 f365xx 字符串常量遵守某些特定属性,它似乎很容易反转。请注意,cArr 是一个接一个填充的,每个字符彼此独立。我们可以尝试同时使用字符和字符串的长度来尝试解码输入i。具体来说,

  • 单个字符将为我们提供i10 的候选者,这将为我们提供charAt 的候选者。重复所有字符,希望每个字符只有一个候选人,并且该候选人会给我们i7/i2 -> i2/i3 -> i 如果字符串是“仁慈的”。
  • 如果字符串不是仁慈的,那么字符串的长度将为我们提供charAt2 的候选者,它与charAt 的候选者一起,将为我们提供i8/i6 的候选者。希望只有一对候选对 i6/i8 -> i5/i6 -> -> i4 -> i 如果字符串常量是仁慈的。

如果字符串仍然不仁,那么它是无解的,因为函数不是一对一的。

我现在将概述 2 个要点的算法,但作为免责声明,我没有对此进行测试,它只是伪代码。

从一个字符

假设您从第一个字符 cArr[0] 开始。如果我们关注 for 循环中的 3 行,

int i10 = charAt + i9;
int charAt3 = f3651b[i10 / 8192].charAt(i10 % 8192) & 65535;
cArr[i9] = f3650a[charAt3 / 8192].charAt(charAt3 % 8192);

然后我们可以通过查找cArr[0]f3650a中出现的位置得到charAt3。例如,

charAt3candidates = []
for i = 0 to length(f3650a)-1:
  indexCandidates = f3650[i].indexOf(cArr[0])
  for indexCandidate in indexCandidates:
    charAt3candidate = i * 8192 + indexCandidate
    if indexCandidate >= 8192 or charAt3candidate >= 65536:
      continue
    charAt3candidates.append(charAt3candidate)

请注意,我们会过滤掉 indexCandidate &gt;= 8192charAt3candidate &gt;= 65536,因为模数和按位与无法获得更大的值(x &amp; 65535 == x % 65536,因为 65536 = 2^16)。

执行类似的过程来找到i10 的候选者并减去i9 以获得charAt 的候选者。如果您有多个候选者,请对cArr 中的每个字符重复此过程,并仅保留对cArr 中的每个字符有效的charAt 的候选者。即使对cArr 中的每个字符都重复了一遍,你可能仍然有很多候选人。

对于charAt的每个候选,使用charAt的表达式的右半部分:

charAt % 65536 = (str.charAt(i7) &amp; 65535)

结合str = f3652c[i2] 尝试查找i2/i7,就像我们尝试查找charAt3i10 一样。请注意,表达式的左半部分 ((str.charAt(i7 + 1) &amp; 65535) &lt;&lt; 16) 无关紧要(目前)。希望并祈祷这只会为您提供i2/i7 的一种可能选择。如果是这样,用它找到i2/i3 -> i。如果有多个选项,那么我们必须尝试使用​​字符串的长度。

从字符串的长度

字符串的长度为我们提供了charAt2,我们可以使用与之前类似的过程来找到i8str2 (i5) 的所有候选对象。请注意,在此过程中,我们必须尝试使用​​ charAt 的所有可能候选者。希望只剩下一对i8/i5 的候选对。如果是这样,用它找到i5/i6 -> i4 -> i。如果候选者多于1个,则该函数不是一对一的,不可能反转。

祝你好运!

【讨论】:

  • 我不确定,但我认为您误解了这个问题;当 OP 写“一个可能的反向代码?要将纯字符串转换成这个?”时,您将其理解为“一种与 m5192a 相反的方法,将字符串转换为整数”,但我 认为 OP 的意思更像是“一种采用生成此混淆代码的字符串的方法”。 (但我可能是错的。)
  • 哦,确实,我误会了,感谢您指出这一点。澄清一下,一个示例应用程序可能是:OP 有一条秘密消息,他想与他的朋友分享 - 他公开分享代码,但只告诉他的朋友 int i,它将生成秘密消息。我相信您在问题中添加了关键字“混淆”,这非常有帮助。 @PedroGaldino OP,你能澄清一下这是否是正确的解释吗?
  • 也许只有通用的密码学方法,如公私钥(即 RSA)或对称(即 AES)可以解决这个问题。您可以将加密消息和公钥(如果适用)作为字符串常量包含在内,然后代码将只是解密函数,其中输入 i 是私钥。
猜你喜欢
  • 2018-09-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-28
  • 2023-04-01
  • 2016-06-10
  • 1970-01-01
相关资源
最近更新 更多