【问题标题】:Need help explain an obfuscated C++ code?需要帮助解释混淆的 C++ 代码吗?
【发布时间】:2011-01-22 01:41:21
【问题描述】:


这段代码 sn-p 把我逼疯了,谁能帮我解释一下?

#include <stdio.h>
char*_="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX";
int main(int l){for(l+=7;l!=putchar(010);++l);if(*(++_))main
    (*_!=88?(putchar(*_^073)|putchar(33))&1:0xffff2a8b);}

谢谢,
陈阮

【问题讨论】:

  • 放火烧这段代码。
  • @Fred Larson:我用谷歌搜索,但找不到任何相关信息。你能分享一些光吗?
  • 你是在问main 是否可以调用main,还是你在问那个代码的解释?这是两个完全不同的问题。请编辑以使标题与问题匹配。
  • @Chan:代码是故意编码的,因此无法阅读。我们可以努力解决它,但除非你是原作者,否则它永远不会完全清楚。

标签: c obfuscation


【解决方案1】:

为了理解这段代码是如何工作的,开始以一种可读的方式重写它:

#include <stdio.h>

char*_="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX";

int main(int l)
{
    for( l += 7; l != putchar(010); ++l ) {
    }

    if( *(++_) ) {
        main( ( *_ != 88 ) ? ( putchar(*_^073) | putchar(33) )&1 : 0xffff2a8b );
    }

    return 0;
}

现在让我们理解它:

  • 它的参数l(如果你在没有参数的情况下运行这个程序,它将是1)增加7(它变成8)

  • 循环将打印 010(八进制表示 8:ascii 退格)直到 l==8(因此当你运行程序时它不会做任何事情

  • 如果_ 指向的下一个字符(现在是x)不同于0(这可能意味着“直到我们到达_ 的末尾”),则调用main,但让我们看看当我们评估它的参数时会发生什么:

    • _当前指向的字符与88不同(88在ascii中是x),因此main的参数将是表达式( putchar(*_^073) | putchar(33) )&amp;1的结果:

      在评估main的参数时,将打印两个字符

      • 第一个是:*_^073,就是这样,120^59(因为x在ascii中是120,而八进制中的073在十进制中是59),即67: 120(@ 987654337@) XOR 59(0b111011) = 67 0b1000011

      • 第二个是 33 (!)

      main 参数将是 (67|33)&amp;1 的结果,即 1

如果您真的想了解细节中发生了什么,您将不得不继续这项工作,但您可以通过运行程序来查看发生了什么(也许在某处放置usleep(10000),这样您实际上可以看到输出)。它将写入一个循环字符串“Corsix!”。

编写这样的程序非常简单:一旦确定了算法的工作原理,就很容易生成一个字符串,例如_,它可以让算法生成你想要的东西,但是逆向工程就更多了困难。

【讨论】:

    【解决方案2】:

    虽然这段代码不符合标准,但gcc会编译它,输出与我对代码的分析一致。可悲的是,如果没有更多上下文,我无法真正解释输出。如果我忽略退格,输出看起来像这样:

    C!o!r!s!i!...
    

    为了分析代码,我们将首先对其进行一些格式化:

    #include <stdio.h>
    
    char* _ ="XxTIHRCXCxTIHRXRCxTIHXHRCxTIXIHRCxTXTIHRCxXxTIHRCX";
    
    int main(int l){
        for(l+=7; l != putchar(010); ++l); // 010 = 8 -> backspace char
        if(*(++_))
            main(
                *_ != 88 ? // *_ != 'X'
                    ( putchar(*_ ^ 073) | putchar(33) ) & 1 : // 33 = '!'
                    0xffff2a8b);
    }
    

    在我们继续之前,有几点值得注意:

    1. 如果putchar 成功,则返回它传递的字符。
    2. 在 C 中,以 0 开头的数字实际上是八进制而不是小数。所以 010 真的是十进制数字 8。

    现在请注意,每当输出 _ 指针时,它都会与八进制值 073 进行异或运算。如果我们将其应用于整个字符串,我们会得到:

    cCorsixcxCorsicixCorscsixCorcrsixCocorsixCcCorsixc
    

    这开始类似于我们之前看到的输出。让我们继续分析一些更有趣的行:

    for(l+=7; l != putchar(010); ++l); // 010 = 8 -> backspace char
    

    这一行的重点是输出一系列退格。如果 l 等于 1,它将只输出一个退格键。但是,如果它等于其他东西,它就会疯狂地倾倒一卡车的字符。行为取决于 main 的调用方式。在启动时,它似乎总是以值 1 调用(不知道为什么)。

    现在让我们看看递归主调用的组成部分。

    ( putchar(*_ ^ 073) | putchar(33) ) & 1 : // 33 = '!'
    

    这是第一个可能的分支。首先它输出一个 XORed 字符,然后它输出一个“!”字符。如果您查看 33 的位模式,您会注意到 (x | 33) & 1 将始终计算为 1。因此在这种情况下,我们仅在 for 循环中输出一个退格字符。

    另一方面,第二个分支有点棘手,因为传递给 main 的值不是 1。如果您仔细查看程序的输出,您会发现它确实在某个位置输出了一卡车的退格在字符串中。没有上下文,我无法真正说出目标是什么。

    现在我们已经有了所有的部分,让我们重写代码:

    #include <stdio.h>
    
    #define BIG_CONSTANT 42 // Not the actual value.
    
    int main () {
        char* str = "cCorsixcxCorsicixCorscsixCorcrsixCocorsixCcCorsixc";
    
        putchar(8);
    
        char* c = str;
        while (*c != '\0') {
    
            if (*c != 'c') { // 'X' ^ 073 = 'c'
                putchar(*c);
                putchar('!');
                putchar(8);
            }
            else {
                for (int i = 0; i < BIG_CONSTANT; ++i)
                    putchar(8);
            }
            c++;
        }
    }
    

    我的 C 有点生锈,所以它可能无法编译/运行。它仍然应该让您对正在发生的事情有一个很好的了解。

    编辑:好吧,我发布答案有点晚了,我刚刚意识到我的控制台正在打印退格键,而不是仅仅删除字符。所以这就是为什么我有点误解了输出。所以就像接受的答案所说,如果你真的正确处理退格,它会打印 Corsix!。

    【讨论】:

    • @Chan 现在我再看一遍,我想我在某个地方犯了错误。如果您查看 C 代码,所有的 '!'字符将被紧随其后输出的退格键删除。由于行为相当微不足道,我认为分析才是这里真正重要的,所以我不会追查问题。
    猜你喜欢
    • 2019-03-17
    • 1970-01-01
    • 2013-12-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-29
    相关资源
    最近更新 更多