1984年国际混淆C代码竞赛如何赢得参赛作品?

时间:2015-11-05 05:26:29

标签: c deobfuscation

我是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。

2 个答案:

答案 0 :(得分:13)

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

首先简化 - 添加空格

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["]<i;++i){--i;}"]用于运行循环14次。就那么简单。它可以简化为i < 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));

由于jread的值始终为零,因此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循环在main函数中:

   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;
}

第四次简化 - 简化

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

,可以使程序变得微不足道
void write(int j, char const* i, int p);

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

答案 1 :(得分:2)

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

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
}