【问题标题】:Obfuscated scientific calculator. Please explain how it works混淆科学计算器。请解释它是如何工作的
【发布时间】:2013-08-03 17:55:46
【问题描述】:

我试图了解以下程序是如何工作的。它是一个命令行科学计算器。来源取自here。对于 IOCCC 条目来说,它似乎很可读,但显然不是。

#include <stdio.h>
#include <math.h>
#define clear 1;if(c>=11){c=0;sscanf(_,"%lf%c",&r,&c);while(*++_-c);}\
  else if(argc>=4&&!main(4-(*_++=='('),argv))_++;g:c+=
#define puts(d,e) return 0;}{double a;int b;char c=(argc<4?d)&15;\
  b=(*_%__LINE__+7)%9*(3*e>>c&1);c+=
#define I(d) (r);if(argc<4&&*#d==*_){a=r;r=usage?r*a:r+a;goto g;}c=c
#define return if(argc==2)printf("%f\n",r);return argc>=4+
#define usage main(4-__LINE__/26,argv)
#define calculator *_*(int)
#define l (r);r=--b?r:
#define _ argv[1]
#define x

double r;
int main(int argc,char** argv){
  if(argc<2){
    puts(
      usage: calculator 11/26+222/31
      +~~~~~~~~~~~~~~~~~~~~~~~~calculator-\
      !                          7.584,367 )
      +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
      ! clear ! 0 ||l   -x  l   tan  I (/) |
      +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
      ! 1 | 2 | 3 ||l  1/x  l   cos  I (*) |
      +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
      ! 4 | 5 | 6 ||l  exp  l  sqrt  I (+) |
      +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+
      ! 7 | 8 | 9 ||l  sin  l   log  I (-) |
      +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0
    );
  }
  return 0;
}

它在 gcc 4.7.2 (Linux) 上使用 -Wall 编译而没有警告。我试图简化它,但是对下面给出的稍微修改的形式进行任何进一步的更改都会产生意想不到的结果(不正确的输出)。

#include <stdio.h>
#include <math.h>
#define clear 1;if(c>=11){c=0;sscanf(_,"%lf%c",&r,&c);while(*++_-c);}\
  else if(argc>=4&&!main(4-(*_++=='('),argv))_++;g:c+=
#define puts(d,e) return 0;}{double a;int b;char c=(argc<4?d)&15;\
  b=(*_%__LINE__+7)%9*(3*e>>c&1);c+=
#define I(d) (r);if(argc<4&&*#d==*_){a=r;r=usage?r*a:r+a;goto g;}c=c
#define return if(argc==2)printf("%f\n",r);return argc>=4+
#define usage main(4-__LINE__/26,argv)
#define calculator *_*(int)
#define l (r);r=--b?r:
#define _ argv[1]
#define x

double r;
int main(int argc,char** argv){
  if(argc<2){
    puts(
      usage: calculator 11/26+222/31
      +calculator-\
      !                          7.584,367 )
      +
      ! clear ! 0 ||l   -x  l   tan  I (/) |
      +
      ! 1 | 2 | 3 ||l  1/x  l   cos  I (*) |
      +
      ! 4 | 5 | 6 ||l  exp  l  sqrt  I (+) |
      +
      ! 7 | 8 | 9 ||l  sin  l   log  I (-) |
      +(0);
  }
  return 0;
}

有人可以解释一下它是如何工作的吗?

【问题讨论】:

  • 研究这个源代码的预处理形式,也许用gcc -C -E obfusc.c | grep -v '^#' | indent &gt; obfusc.i然后看里面̀obfusc.i
  • 当然不是。 IOCCC 条目至少需要我两个小时来分析(我会在试图理解它的作用的过程中完全重构代码),而冗长的解释可能需要一天的时间来编写,并且完全超出了本网站的范围恕我直言。
  • 注意__LINE__ 宏,它对换行很敏感。用于标识/*+- 运算符。

标签: c obfuscation


【解决方案1】:

它扩展为如下所示:

double r;
int
main (int argc, char **argv)
{
  if (argc < 2)
    {
      if (argc == 2)
    printf ("%f\n", r);
      return argc >= 4 + 0;
    }
  {
    double a;
    int b;
    char c = (argc < 4 ? main (4 - 21 / 26,
                   argv) : *argv[1] * (int) 11 / 26 + 222 / 31 +
          ~~~~~~~~~~~~~~~~~~~~~~~~*argv[1] * (int) -!7.584) & 15;
    b = (*argv[1] % 21 + 7) % 9 * (3 * 367 >> c & 1);
    c += +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+!1;
    if (c >= 11)
      {
    c = 0;
    sscanf (argv[1], "%lf%c", &r, &c);
    while (*++argv[1] - c);
      }
    else if (argc >= 4 && !main (4 - (*argv[1]++ == '('), argv))
      argv[1]++;
  g:c += !0 || (r);
    r = --b ? r : -(r);
    r = --b ? r : tan (r);
    if (argc < 4 && *"/" == *argv[1])
      {
    a = r;
    r = main (4 - 23 / 26, argv) ? r * a : r + a;
    goto g;
      }
    c = c | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+!1 | 2 | 3 || (r);
    r = --b ? r : 1 / (r);
    r = --b ? r : cos (r);
    if (argc < 4 && *"*" == *argv[1])
      {
    a = r;
    r = main (4 - 25 / 26, argv) ? r * a : r + a;
    goto g;
      }
    c = c | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+!4 | 5 | 6 || (r);
    r = --b ? r : exp (r);
    r = --b ? r : sqrt (r);
    if (argc < 4 && *"+" == *argv[1])
      {
    a = r;
    r = main (4 - 27 / 26, argv) ? r * a : r + a;
    goto g;
      }
    c = c | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+!7 | 8 | 9 || (r);
    r = --b ? r : sin (r);
    r = --b ? r : log (r);
    if (argc < 4 && *"-" == *argv[1])
      {
    a = r;
    r = main (4 - 29 / 26, argv) ? r * a : r + a;
    goto g;
      }
    c = c | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(0);
  }
  if (argc == 2)
    printf ("%f\n", r);
  return argc >= 4 + 0;
}

它仍然不完全可读,但至少现在没有什么对你隐藏。你应该能够做你的简化而不会被咬得那么厉害。

出于@cmaster 所说的相同原因,我不会详细解释。

【讨论】:

    猜你喜欢
    • 2020-10-20
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    • 2014-09-16
    • 1970-01-01
    • 2017-11-03
    • 2017-11-05
    • 2018-05-07
    相关资源
    最近更新 更多