这种逆向工程算法是如何工作的?
How does this reverse-engineered algorithm work?
实际算法函数为:
output[i] = ( (129 * input[i]) XOR input[i-1]) % 256 //input[-1] = 0
对此有多种解决方案。通常的做法是:
var output = [0, 129, 3, 129, 7, 129, 3, 129, 15, 129, 3, 129, 7, 129, 3, 129];
var outputToInputArray = function(array) {
var input = [];
var outputToInput = function(dig, lastInput) {
var current = dig;
while(true) {
if (!((current ^ lastInput) % 129)) {
return (current ^ lastInput)/129;
}
current += 256;
}
}
for(var i = 0; i < output.length; i++) {
input.push(outputToInput(output[i], i>0 ? input[i-1] : 0));
}
return input;
}
console.log(outputToInputArray(output));
然而,我刚好遇到了:
output = [0, 129, 3, 129, 7, 129, 3, 129, 15, 129, 3, 129, 7, 129, 3, 129]
var input = [];
for(var i =0; i < output.length; i++) {
lastInput = input.length < 1 ? 0 : input[i-1];
input.push(((output[i] ^ lastInput) * 129) % 256);
}
console.log(input);
当要求反转函数时要遵循的想法是代数反转函数。然而,第二种解决方案似乎以一种在数学上不应该有效的方式简化了反转函数!但它有效!请帮忙!
P.S。预期输出为 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
首先,你的"hash function"并不是传统意义上的哈希函数。哈希函数通常采用输入(可以是可变大小,例如字符串)并将其转换为固定位数的单个值。这类函数是不能真正逆向的,因为在转换过程中丢失了很多位的数据;你不能从 4 位重建 100 位。
您的函数将一个字节列表转换为另一个等长的字节列表。看起来它需要当前输入,运行通过函数 x => (x*129)%256
传递它,然后 xor
将它与之前的输入传递。
函数f(x) = (x*129) % 256
是有趣的部分。如果输入是偶数,则输出是相同的数字。如果输入是奇数,则输出是第 7 位(第 127 位)反转的输入。 (尝试自己插入一些值。)因此,f(x)
是它自己的倒数; f(f(x)) == x
.
因此,整个"hash function"可以这样反转:
xor
当前哈希值与前一个输入值,或者 0
如果第一个
- 运行结果通过
f(x)
函数取反f(x)
时的值
- 对每个值重复
...这就是您最后一段代码所做的。我不确定第一个。
Note: after writing up this answer, I re-read the answer by qxz, and
realized that everything covered here is also covered in qxz's answer.
But I've decided to post this anyways, since a slightly different
format may be helpful to some.
要了解其工作原理,您只需计算
y = (129 * x) % 256;
对于 0 到 255 之间的每个 x。从偶数开始
for ( x = 0; x < 256; x += 2 ) {
y = (129 * x) % 256;
console.log(y);
}
输出为
0 0
2 2
4 4
6 6
8 8
10 10
12 12
14 14
... ...
换句话说,当您乘以 129 模 256 时,偶数不会改变。
奇数的输出是
1 129
3 131
5 133
7 135
9 137
11 139
... ...
125 253
127 255
129 1
131 3
133 5
... ...
换句话说,乘以 129 模 256 等于将 128 加到模 256 上。所以当你这样做两次时,你会得到原来的数字:(x + 128 + 128) % 256 = x
公式的其余部分对此没有任何影响。模 256 丢弃位 7 以上的任何位,保留低 8 位。 XOR 对第 7 位以上的位没有影响,它只是反转一些较低的 8 位。因此 XOR 和模 256 之间没有相互作用。XOR 只影响低 8 位,而模只影响高位。
意思是在逆向计算的时候,可以先异或取回低8位。然后乘以 129 模 256 要么什么都不做(如果数字是偶数),要么加上 128 模 256(如果数字是奇数)。无论哪种方式,您都会得到原来的号码。
实际算法函数为:
output[i] = ( (129 * input[i]) XOR input[i-1]) % 256 //input[-1] = 0
对此有多种解决方案。通常的做法是:
var output = [0, 129, 3, 129, 7, 129, 3, 129, 15, 129, 3, 129, 7, 129, 3, 129];
var outputToInputArray = function(array) {
var input = [];
var outputToInput = function(dig, lastInput) {
var current = dig;
while(true) {
if (!((current ^ lastInput) % 129)) {
return (current ^ lastInput)/129;
}
current += 256;
}
}
for(var i = 0; i < output.length; i++) {
input.push(outputToInput(output[i], i>0 ? input[i-1] : 0));
}
return input;
}
console.log(outputToInputArray(output));
然而,我刚好遇到了:
output = [0, 129, 3, 129, 7, 129, 3, 129, 15, 129, 3, 129, 7, 129, 3, 129]
var input = [];
for(var i =0; i < output.length; i++) {
lastInput = input.length < 1 ? 0 : input[i-1];
input.push(((output[i] ^ lastInput) * 129) % 256);
}
console.log(input);
当要求反转函数时要遵循的想法是代数反转函数。然而,第二种解决方案似乎以一种在数学上不应该有效的方式简化了反转函数!但它有效!请帮忙!
P.S。预期输出为 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
首先,你的"hash function"并不是传统意义上的哈希函数。哈希函数通常采用输入(可以是可变大小,例如字符串)并将其转换为固定位数的单个值。这类函数是不能真正逆向的,因为在转换过程中丢失了很多位的数据;你不能从 4 位重建 100 位。
您的函数将一个字节列表转换为另一个等长的字节列表。看起来它需要当前输入,运行通过函数 x => (x*129)%256
传递它,然后 xor
将它与之前的输入传递。
函数f(x) = (x*129) % 256
是有趣的部分。如果输入是偶数,则输出是相同的数字。如果输入是奇数,则输出是第 7 位(第 127 位)反转的输入。 (尝试自己插入一些值。)因此,f(x)
是它自己的倒数; f(f(x)) == x
.
因此,整个"hash function"可以这样反转:
xor
当前哈希值与前一个输入值,或者0
如果第一个- 运行结果通过
f(x)
函数取反f(x)
时的值 - 对每个值重复
...这就是您最后一段代码所做的。我不确定第一个。
Note: after writing up this answer, I re-read the answer by qxz, and realized that everything covered here is also covered in qxz's answer. But I've decided to post this anyways, since a slightly different format may be helpful to some.
要了解其工作原理,您只需计算
y = (129 * x) % 256;
对于 0 到 255 之间的每个 x。从偶数开始
for ( x = 0; x < 256; x += 2 ) {
y = (129 * x) % 256;
console.log(y);
}
输出为
0 0
2 2
4 4
6 6
8 8
10 10
12 12
14 14
... ...
换句话说,当您乘以 129 模 256 时,偶数不会改变。
奇数的输出是
1 129
3 131
5 133
7 135
9 137
11 139
... ...
125 253
127 255
129 1
131 3
133 5
... ...
换句话说,乘以 129 模 256 等于将 128 加到模 256 上。所以当你这样做两次时,你会得到原来的数字:(x + 128 + 128) % 256 = x
公式的其余部分对此没有任何影响。模 256 丢弃位 7 以上的任何位,保留低 8 位。 XOR 对第 7 位以上的位没有影响,它只是反转一些较低的 8 位。因此 XOR 和模 256 之间没有相互作用。XOR 只影响低 8 位,而模只影响高位。
意思是在逆向计算的时候,可以先异或取回低8位。然后乘以 129 模 256 要么什么都不做(如果数字是偶数),要么加上 128 模 256(如果数字是奇数)。无论哪种方式,您都会得到原来的号码。