• 1987年国际C语言混乱代码大赛获奖的一行代码


    最近CoolShell博主做了一个很有意思的在线puzzle,这些谜题很有趣同时也有一定的难度。由于水平有限,我并没有通关,我觉得这些题还是很值得一做的,从中可以学到很多东西。

    例如其中的第二题:


    题目中给出了一个键盘和一行看不懂的字符串。我们发现这个键盘的键盘布局和现在通用的键盘(QWERTY键盘)不一样,它叫做Dvorak键盘。这里就不多作解释了,详细的可以去Google。键盘图片明显在提示我们:要通过两种键盘的布局映射,将给出的字符串转换成QWERTY键盘下的输出。当然,你可以自己一对一写出来,不过在线转换工具更方便。

    macb() ? lpcbyu(&gbcq/_21%ocq12_=w(gbcq)/_dak._=}_ugb_[0q60)s+
    转换之后得到:

    main() { printf(&unix["21%six12"],(unix)["have"]+"fun"-0x60);}
    这是1987年国际C语言混乱代码大赛(The International Obfuscated C Code Contest, IOCCC)一等奖的获奖代码,由贝尔实验室的David Korn提交。当然平时我们不会写出这么复杂难懂的代码,但是分析这样的代码却可以扩展我们的知识。

    int main() 
    {
    	/* unix被编译器内定为一个宏 
    	 * 相当于#define unix 1     */
    	
    	printf("unix=%d
    ", unix); /* =1 */	
    	
    	/* 打印字符串"un",因为"fun"是个字符数组
    	 * "fun"+1相当于字符指针右移,指向"un" */
    	printf("%s
    ","fun"+1);
    
    	/* "have"是个字符数组,"have"[1]即字符a
    	 * 输出97,即第二个字符'a'的ASCII值。*/
    	printf("%d
    ", "have"[1]);
    	printf("%d
    ", 'a');
    
    	/* 在C语言中,x[1] = 1[x] */
    	printf("%d
    ", (1)["have"]);
    
    	/* 97 - 96 = 0x61 - 0x60 = 1 */
    	printf("%d
    ", (1)["have"] - 0x60);
    
    	/* 所以 "fun"+((1)["have"]-0x60) 相当于"fun"+1,输出"un" */
    	printf("%s
    ", "fun" + ((1)["have"] - 0x60));
    
    	/* 将其中的1用unix代替 */
    	printf("%s
    ", (unix)["have"]+"fun"-0x60);
    
    	/* 以上为后半部分 = "un" */
    
    	/* 下面两个都输出"bcde", 因为指针都是从'b'开始 */
    	printf("%s
    ", "abcde" + 1);
    	printf("%s
    ", &"abcde"[1]);
    
    	/* &"abcde"[1] == &(1)["abcde"]  输出一样 */
    	printf("%s
    ", &(1)["abcde"]);
    
    	/* 1用unix代替 */
    	printf("%s
    ", &unix["abcde"]);
    
    	/* 下面输出"%six" 并换行 */
    	printf("%s", &"?%six
    "[1]);
    
    	/* 注意:
    	   12 = 0x0a = 
    , 
    	   第一个字符 21 被跳过
    	    是空字符  */
    
    	/* 同样输出"%six" 并换行 */
    	printf("%s", &"21%six12"[1]);
    
    	/* 相当于这样 */
    	printf("%s", &unix["21%six12"]);
    
    	/* 把字符串"%six
    "当作格式,输出"ABix" */
    	printf(&unix["21%six12"], "AB");
    
    	/* 相当于这样 */
    	printf("%six
    ", "AB");
    
    	/* 所以下面的可以输出"unix" */
    	printf("%six
    ", (unix)["have"]+"fun"-0x60);
    	
    	/* 至此,问题解决!!!输出"unix" */
    	printf(&unix["21%six12"],(unix)["have"]+"fun"-0x60);
    
    	return 0;
    }

    这段代码主要用到了x[a]和指针运算的一些知识,相信上面的步骤和注释已经很清楚了,最终结果就是输出unix




  • 相关阅读:
    Win7 on VirtualBox 看不到 usb device
    framebuffer line_length 參數
    booting logo & booting animation
    charing animation
    vim
    [筆記] Ubuntu Linux 使用 apt-get 指令移除軟體並清理遺留的垃圾
    git 指令
    adb devices 偵測不到 手機
    apt-get 相關設定
    Ubuntu 14 設定 遠端連線,讓別台電腦可以連線進來
  • 原文地址:https://www.cnblogs.com/songlee/p/5738125.html
Copyright © 2020-2023  润新知