Нужна помощь, чтобы объяснить запутанный код C ++? - PullRequest
7 голосов
/ 18 января 2011


Этот фрагмент кода сводил меня с ума, кто-нибудь может помочь мне объяснить это?

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

Спасибо,
Чан Нгуен

Ответы [ 2 ]

7 голосов
/ 21 января 2011

Чтобы понять, как работает этот код, начните переписывать его читабельным образом:

#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 backspace) до l==8 (таким образом, он ничего не сделает при запуске программы

  • , если следующий символ, на который указывает _ (сейчас x), отличается от 0 (это, вероятно, будет означать "пока мы не достигли конца _"), вызывается main, но давайте посмотрим, что происходит, пока мы оцениваем его параметры:

    • символ, на который в данный момент указывает _, отличается от 88 (88 - x в ascii), поэтому параметр для main будет результатом выражения ( putchar(*_^073) | putchar(33) )&1:

      при оценке параметра main будут напечатаны два символа

      • первое: *_^073, вот и все, 120^59 (поскольку x равно 120 в ascii, а 073 в восьмеричном - 59 в десятичном виде), что составляет 67: 120 (0b1000011) XOR 59 (0b111011) = 67 0b1000011

      • второй 33 (!)

      Параметр

      main будет тогда результатом (67|33)&1, который равен 1

Если вы действительно хотите понять, что происходит в деталях, вам придется продолжить эту работу, но вы сможете увидеть, что происходит, запустив программу (возможно, поместите куда-нибудь usleep(10000), чтобы вы можете увидеть результат). Будет написана вращающаяся строка "Corsix!".

Написание такой программы довольно просто: как только вы решите, как работает ваш алгоритм, легко сгенерировать строку, такую ​​как _, которая заставляет алгоритм генерировать то, что вы хотите, но для обратного инжиниринга это намного больше трудно.

4 голосов
/ 21 января 2011

Хотя этот фрагмент кода не соответствует стандарту, 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.

Теперь обратите внимание, что всякий раз, когда указатель _ выводится, он XOR с восьмеричным значением 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 немного ржавый, так чтоможет не скомпилировать / запустить.Это все еще должно дать вам хорошее представление о том, что происходит.

РЕДАКТИРОВАТЬ: Ну, я немного опоздал с публикацией своего ответа, и я только что понял, что моя консоль немного печатает backspacesбуквально вместо того, чтобы просто удалить символы.Вот почему я несколько неверно истолковал вывод.Таким образом, как сказано в принятом ответе, если вы на самом деле правильно обрабатываете backspace, он печатает Corsix!.

...