Need help explaining obfuscation code in C ++?


This piece of code drove me crazy, can anyone help me explain this?

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

Thanks,
Chan Nguyen

+7
source share
2 answers

To understand how this code works, start rewriting it in a readable way:

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

Now let's understand this:

  • its parameter l (which will be equal to 1 if you run this program without parameters) increases by 7 (this becomes 8)

  • the loop will print 010 (octal for 8: ascii backspace) to l==8 (while it will not do anything when the program starts

  • if the following character, denoted by _ (it x now), is different from 0 (this probably means "until we reach the end of _ "), main is called but it allows you to see what happens when we evaluate its parameters:

    • the character currently indicated by _ differs from 88 (88 is x in ascii), so the main parameter will be the result of the expression ( putchar(*_^073) | putchar(33) )&1 :

      when evaluating the main parameter, two characters will be printed

      • the first of them: *_^073 , that it is 120^59 (since x is 120, in ascii and 073 in octal is 59 in decimal), which is 67 : 120 ( 0b1000011 ) XOR 59 ( 0b111011 ) = 67 0b1000011

      • the second - 33 ( ! )

      main will then be the result of (67|33)&1 , which is 1

If you really want to understand what is happening in the details, you will have to continue this work, but you can see what is happening by running the program (maybe put usleep(10000) somewhere so that you can see the result). He will write a line for rotation " Corsix! ".

Writing such a program is pretty simple: as soon as you decide how your algorithm works, it's easy to create a string, such as _ , that makes the algorithm generate what you want, but for reverse engineering it is much more difficult.

+7
source

Although this piece of code is not standard, gcc will compile it, and the result will be consistent with my code analysis. Unfortunately, I cannot interpret the output without any extra context. If I ignore backspaces, the output looks something like this:

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

To analyze the code, we start by formatting it a bit:

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

Here are a few things to note before we go any further:

  • If putchar succeeds, it returns the char that was passed.
  • In C, numbers starting with 0 are actually octal, not decimal. So 010 is indeed the decimal number 8.

Now note that whenever the _ pointer is displayed, it is XORed with the octal value 073. If we apply this on the entire line, we get:

 cCorsixcxCorsicixCorscsixCorcrsixCocorsixCcCorsixc 

This begins to resemble the result we saw earlier. We continue by analyzing a few more interesting lines:

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

The point of this line is the output of a number of inverse spaces. If l is 1, it gives out only one backspace. But, if it is equal to something else, a truck with glasses flies into landfills. The behavior depends on what is called main. At startup, it is always called with a value of 1 (I don’t know why).

Now consider the components of a recursive main call.

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

This is the first possible branch. First, it displays one of the XORed characters, and then displays '!' char. If you look at bit pattern 33, you will notice that (x | 33) and 1 will always be evaluated at 1. Thus, in this case, we only output one inverse character in the for loop.

The second branch, on the other hand, is a bit more complicated, because the value passed to main is not 1. If you look closely at the program output, you will notice that it displays the load on the packages in some place on the line. Without context, I cannot say what the goal is.

Now that we have all the parts, rewrite the code:

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

My C is a little rusty, so it cannot compile / run. This should still give you a good idea of ​​what is happening.

EDIT: Well, I was a little late in sending my answer, and I only realized that my console was printing backspaces a bit literally, instead of just deleting characters. Therefore, I misinterpreted the conclusion. Therefore, as in the accepted answer, if you handle the backspaces correctly, it prints Corsix !.

+4
source

All Articles