Gynvael’s mission 004 – the weird way ;)

The mission description isĀ here. It’s in Polish, but it doesn’t really matter. We just have to figure out the password from this code:

#include
int check(char*b){char*p;for(p=b;*p;p++);if(((p-b)^42)!=47)return(
~0xffffffff);unsigned long long ch=0x1451723121264133ULL;for(p=b;*
p;p++)ch=((ch<<9)|(ch>>55))^*p;return!!(14422328074577807877ULL==
ch);}int main(void){char buf[1234];scanf("%1233s",buf);puts("nope"
"\0good"+check(buf)*(6-1));return 0;}

which is simply an obfuscated C.
First: formatting:

#include <stdio.h>

int check(char* b)
{
    char* p;
    for ( p = b; *p; p++ )
        ;

    if ( ( ( p - b ) ^ 42 ) != 47 )
        return ( ~0xffffffff );

    unsigned long long ch = 0x1451723121264133ULL;
    for ( p = b; *p; p++ )
        ch = ( ( ch << 9 ) | ( ch >> 55 ) ) ^ *p;

    return !!( 14422328074577807877ULL == ch );
}

int main(void)
{
    char buf[1234];
    scanf("%1233s", buf);
    puts( "nope\0good" + check( buf ) * ( 6 - 1 ) );
    return 0;
}

Now things that are pure noise:

#include <stdio.h>
#include <string.h>

int check(char* b)
{
    if ( ( strlen( b ) ^ 42 ) != 47 )
        return 0;

    unsigned long long ch = 0x1451723121264133ULL;
    for ( char* p = b; *p; p++ )
        ch = ( ( ch << 9 ) | ( ch >> 55 ) ) ^ *p;

    return 0xC82666F8975A8A05ULL == ch;
}

int main(void)
{
    char buf[1234];
    scanf("%1233s", buf);
    puts( "nope\0good" + check( buf ) * 5 );
    return 0;
}

Let's check what the return value of check should be. We can rewrite this line:

puts( "nope\0good" + check( buf ) * 5 );

to

puts( check( buf ) == 1 ? "good" : "nope" );

so it returns 1 for a good password.
In the check itself we have two return statements. The first one is a length restriction. There’s some nice XOR; and what do we know about XOR?
a ^ b = c ==&gt; c ^ b = a, thus our password length is 47 ^ 42 = 5.

What about the bit shifting magic? That one came to me as a surprise. I took a look at the generated assembly and it’s simply a rotate-left by 9 bits. So each time we rotate the magic value by 9 and then XOR the last 8 bits (sizeof char). At the end we check if the result is another magic constant.

Because we never modify the same bits twice we can just rotate ch once by 45 bits. With that knowledge we can rewrite the code a bit:

int check(char* b)
{
    if ( strlen( b ) != 5 )
        return 0;

    unsigned long long ch = 0xC826628A2E462424ULL;
    unsigned long long pw = 0x0ULL;

    for ( char* p = b; *p; p++ )
        pw = ( ( pw << 9 ) | *p );

    return ( pw ^ ch ) == 0xC82666F8975A8A05ULL;
}

And there is the XOR! Time to recover the password from the already known formula:

#include <stdio.h>

int main(void)
{
    unsigned long long ch    = 0xC826628A2E462424ULL;
    unsigned long long magic = 0xC82666F8975A8A05ULL;
    unsigned long long pw = ( magic ^ ch );
    for( int i = 45; i >= 0; i -= 9 )
        putchar( (char)(pw >> i) );

    return 0;
}

This code prints GWGW! when executed.

Advertisements