Impossible Codification

在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);
posted @ 2012-02-19 18:44  atyuwen  阅读(2014)  评论(1编辑  收藏  举报