在iq的blog上看到这样一段代码:
int t[] = {0x4845A956, 0x586DEE32, 0x7E6B9933, 0x0D059D58, 0}; int ch = t[0] + t[1] + t[2] + t[3]; t[0]^=ch; t[1]^=ch; t[2]^=ch; t[3]^=ch; char *str = (char*)t;
把str打印出来是这样的:Egad! It WORKS!!
而如果将t的改为这样:
int t[] = {0x151ba3a, 0x10abc1a, 0x118a113, 0x1e08bc0b, 0 };
那么此时str为: Hi, how are you?.
看起来很神奇吧。下面就来的推导一下怎么设置t的值,以使得str为任意字符串.
令 x = t[0], y = t[1], z = t[2], w = t[3]
我们需要将x, y, z, w经过指定的变换之后得到指定的x’, y’, z’, w’. 变换的过程为:
s = x + y + z + w
x’ = x ^ s
y’ = y ^ s
z’ = z ^ s
w’ = w ^ s
现在是已知x’, y’, z’, w’, 要求x, y, z, w. 这看起来有点麻烦,因为有4个未知数,但稍稍变换一下可以发现,实际上只需要求一个未知数 s 就够了. 将上面的后四式两边同时异或一个s, 得:
x = x’ ^ s; y = y’ ^ s; z = z’ ^ s; w = w’ ^ s.
于是有方程:
s = (x’^ s) + (y’ ^s) + (z’ ^s) + (w’^s)
选定任意一个初始值,进行不动点迭代即可解得 s.
这里有两个疑问,一是方程的解是否存在,二是上面的迭代是否一定会收敛。答案都是肯定的,也很好证明。对于存在性可以得到,若方程右边和式的项数是偶数(在上面是4项),则一定有解。而至于收敛性,因为一旦s的低位确定了,在迭代就不会变化了,而每次迭代至少会确定一个新的位,所于至多32次迭代就会收敛到解。感兴趣的同学可以自己推一下。
好了,现在我们也可以构造出神秘的编码了,试试下面这个:
int t[10] = {0x33106d0f, 0x3351230e, 0x66457026, 0x3f526130,0x7e1b4d67, 0x7a487767, 0x721c682b, 0x764a6d2b, 0x133c0469, 0x133c0447}; int ch = 0; for (int i = 0; i != 10; ++i) ch += t[i]; for (int i = 0; i != 10; ++i) t[i] ^= ch; char *str = (char*)t; printf(str);