【问题标题】:How does this 1984 International Obfuscated C Code Contest winning entry work?这个 1984 年国际混淆 C 代码竞赛获奖作品是如何工作的?
【发布时间】:2015-11-05 05:26:28
【问题描述】:

我是 C 新手,我很想知道这段代码有什么魔力?

int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\
o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}

来源可以在这里找到:http://www.ioccc.org/1984/anonymous.c

以下是代码自带的提示:

不光彩的提及: 匿名

作者太尴尬了,他/她能写出这样的垃圾,所以 我答应保护他们的身份。我会说作者 这个程序与 C 编程有一个众所周知的联系 语言。这个节目是古老的“你好, 世界”程序。读起来像读的东西可能写得像写! 版权所有 (c) 1984,Landon Curt Noll。版权所有。允许 允许用于个人、教育或非营利用途,前提是 此版权和通知全部包含在内,并且仍然保留 不变。所有其他用途必须事先获得书面许可 来自 Landon Curt Noll 和 Larry Bassel。

【问题讨论】:

  • 第 1 步是将其粘贴到您喜欢的代码编辑器中,并修复格式。
  • 我相信codegolf.stackexchange.com 更适合回答这个问题
  • 在代码高尔夫中,它将是 main(){puts("hello, world!");} 或更短的。

标签: c deobfuscation


【解决方案1】:

当您有混淆代码时,您需要清理物理布局、添加一些空白、添加必要的缩进,然后编译代码。来自编译器的警告会告诉你很多关于程序隐藏的一些东西。

First Cut 简化 - 添加空格

int i;
main()
{
   for( ; i["]<i;++i){--i;}"];
          read('-'-'-', i+++"hell\o, world!\n", '/'/'/'));
}

read(j,i,p)
{
   write(j/p+p,i---j,i/i);
}

当使用gcc -Wall 编译程序时,我收到以下警告:

soc.c:2:1: warning: return type defaults to ‘int’ [enabled by default]
 main()
 ^
soc.c: In function ‘main’:
soc.c:4:4: warning: implicit declaration of function ‘read’ [-Wimplicit-function-declaration]
    for( ; i["]<i;++i){--i;}"]; read('-'-'-', i+++"hell\o, world!\n", '/'/'/'));
    ^
soc.c:4:50: warning: unknown escape sequence: '\o' [enabled by default]
    for( ; i["]<i;++i){--i;}"]; read('-'-'-', i+++"hell\o, world!\n", '/'/'/'));
                                                  ^
soc.c: At top level:
soc.c:7:1: warning: return type defaults to ‘int’ [enabled by default]
 read(j,i,p)
 ^
soc.c: In function ‘read’:
soc.c:7:1: warning: type of ‘j’ defaults to ‘int’ [enabled by default]
soc.c:7:1: warning: type of ‘i’ defaults to ‘int’ [enabled by default]
soc.c:7:1: warning: type of ‘p’ defaults to ‘int’ [enabled by default]
soc.c:9:4: warning: implicit declaration of function ‘write’ [-Wimplicit-function-declaration]
    write(j/p+p,i---j,i/i);
    ^
soc.c:9:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
    write(j/p+p,i---j,i/i);
                 ^
soc.c:9:17: warning: operation on ‘i’ may be undefined [-Wsequence-point]
soc.c:10:1: warning: control reaches end of non-void function [-Wreturn-type]
 }
 ^

二次切割简化 - 去混淆

根据上述警告,可以将程序解混淆为:

int i;

void read(int j, char* i, int p);
void write(int j, char* i, int p);

int main()
{
   for( ; i["]<i;++i){--i;}"];
          read('-'-'-', , '/'/'/'));
   return 0;
}

void read(int j, char* i, int p)
{
   write(j/p+p, (i--) - j, 1);
}

以上版本没有编译器警告并且产生相同的输出。

三切简化 - 取消混淆更多

表达式i["]&lt;i;++i){--i;}"] 用于运行循环14 次。就那么简单。可以简化为i &lt; 14

'-'-'-'0

'/'/'/'1

i++ + "hello, world!\n"s + i++ 相同,其中s 可以是char const* s = "hello, world!\n";

for 循环可以简化为:

   char const* s = "hello, world!\n";
   for( ; i < 14; read(0, s+i++, 1));

由于readj的值始终为零,所以read的实现可以简化为:

void read(int j, char* i, int p)
{
   write(0, (i--), 1);
}

表达式(i--) 可以简化为i,因为作为副作用的递减不会改变函数的工作方式。也就是说,上面的函数是:

void read(int j, char* i, int p)
{
   write(0, i, 1);
}

当我们意识到参数j的值总是0并且参数p的值总是1时,我们可以将主函数中的for循环更改为:

   for( ; i < 14; i++)
   {
      write(0, s+i, 1);
   }

因此,整个程序可以简化为:

void write(int j, char const* i, int p);

int main()
{
   int i = 0;
   char const* s = "hello, world!\n";
   for( ; i < 14; i++ )
   {
      write(0, s+i, 1);
   }
   return 0;
}

Fourth Cut Simplification - Make It Trivial

以上版本有一个硬编码号码14。那是s 中的字符数。因此,可以通过将程序更改为:

void write(int j, char const* i, int p);

int main()
{
   write(0, "hello, world!\n", 14);
   return 0;
}

【讨论】:

    【解决方案2】:

    让我们重写一点代码,替换一些表达式并添加 cmets

    int i; // i = 0 by default
    
    main()
    {
        for( ;
            "]<i;++i){--i;}" [i];  // magic: it is the same as i["]<i;++i){--i;}"];
                                   // the important part is that there's 14 chars in the
                                   // string, same length that "hello, world!\n"
                                   // the content of the string has no importance here,
                                   // in the end 'i' will go from 0 to 14
    
            read(0, // since '-' - '-' is equal to 0,
                 "hello, world!\n" + (i++),  // same as i+++"hello, world!\n"
                                          // it is pointers arythmetic
                                          // the second arg to the read
                                          // function defined further points
                                          // to the letter to print
                 1)) // '/' / '/' division result is 1
          ;
    }
    
    // the read function is then always called with
    // j == 0
    // i is a pointer to the char to print
    // p == 1
    // And for the obfuscation fun, the read function will write something :)
    read(j,i,p)
    {
        write(0,  // j/p+p is equal to 0, which is the stdout 
              i,  // i-- - j is equal to i, decrement of i comes later
              1);  // i / i is equal to 1, this means one char to print
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-03-01
      • 2013-09-20
      • 2010-12-13
      • 2013-07-24
      • 2012-11-14
      • 1970-01-01
      相关资源
      最近更新 更多