Coder's Guild Mailing List

Re: obfuscated C code: my nifty sig

Posted by Weasel on 1999-06-11

Matthew Pratt wrote:
> 
> >
> main(i){putchar(354603184>>(i-1)*5&31|!!(i<6)<<6)&&main(++i);}
> 
> Hey I saw a guy on slashdot with something similar in
> his sig (his spelt DAVE), is that where you got it
> from? How do you work out the magic number?
Ok, you got me. I simply stole it. *grin* At least I understood it :)

It is not that hard to get the magic number. I'll expain:

1 main(i)
2   {
3    putchar(354603184>>(i-1)*5&31|!!(i<6)<<6)
4    &&
5    main(++i);
6   }

Ok, lets start at line one; the i actually is the param_count variable.
So if someone would start this program with <prg> <parameter1>
<parameter2> i would be 2. but since noone does it start with parameters
i always equals zero.

line 2 is quiet simply. 'nuff said.
line 4 (the and operator) simply asks to also evaluate line 5. a simply
semicolon (;) would have done too but it would not have looked that
nice.
line 5 now calls main() recursivly with an i that is one greater.
line 6 see line 2

ok, now the killer line: line 3
   354603184>> (i-1)*5  &  31 |  ! !(i<6)  <<  6
              (     * )           (!     )
  (         >>         )        (!        )
 (                      &    ) (           <<   )
(                             |                  )

the parenthensis show the precedence of the operators.

putchar simply puts out one character (really!) but the question is
which one. let's look at the first part:

354603184>>(i-1)*5&31

we have a magic numer which we shift to the right (i-1)*5 bits, i.e. we
divide through 32^(i-1) afterwards we do a logical AND with
11111b=1fh=31 so that this value is in the range of 0 to 31 both
inclusively.

the second part:
!!(i<6)<<6

forget about those 2 negations. they are useless and just there so that
the program fits excatly into the line:)

so we have:
(i<6)<<6

where (i<6) is a value either 0 or 1 and <<6 shifts this 6 bits to the
left resulting in either 0 or 64.
if i is <6 we get 64 and if i>=6 we get 0.


then we do a bitwise OR on both of these.

what we now have is:
a number between 0 and 31 (determined by the magic number and i) and 0
or 64 depending on (i<6)

iow if i < 6 we get values above 64 ('A' == 65, ..) and when i finally
gets 6 we have a value in the range from 0 to 31 in my case 10 which is
a newline.



so the number to get
ABCDE

is:
                 1+
                   32*(2+
                         32*(3+
                               32*(4+
                                     32*(5+
                                           32*10
                                        )
                                  )
                            )
                     
)                                                                                                                


where 1 to 5 return the A to E and 10 is for the newline.



any questions?

-- 
Weasel                    http://www.cosy.sbg.ac.at/~ppalfrad/
main(i){putchar(354603184>>(i-1)*5&31|!!(i<6)<<6)&&main(++i);}
     We have full klingon console support just in case.
                         -- Alan Cox on linux-kernel