Gynvael’s mission PL-009

This is a solution of a “mission” created by Gynvael Coldwind and presented on the YouTube video. The actual mission text (in polish)
Solution code (in GO again): https://github.com/jzakrzewski/gyn-pl-009
Translation would be something along this:

Our technicians received a sound recording containing strange squeals. We got the recording from a local radio amateur and you can download it from

https://goo.gl/NeJHD2

If you can, please give our technicians a hand with this. They are currently occupied fixing our electrohydroturbobulbulator.

Good luck!

First glance

When you download and unpack the file, you’ll get a normal *.wav. Nothing fancy this time (uffff…). I used Audacity to listen and take a look. When you play it, you’ll notice only two distinct sounds and looking at the sound wave you can easily tell that each squeal takes 1 second. If it’s not a kind of binary encoding, then I could give up right now. Plotting the spectrum only confirms that there are two main frequencies:
spectrum

What is it?

Gynvael said it could be solved with a pen and a piece of paper and this is how I decided to start. I assumed I was working with bytes (I had no clue if that was the case but it’s the simplest thing to do) and wanted to decode like three of them to have something to begin with. Audacity has been very helpful with the task as it provides a spectrogram view:
spectrogram_view

The first 3 bytes are 01100010, 01001110, and 10100110. And they don’t tell me a thing at first (Gynvael’s secretes are normally ASCII letters). I tried flipping the bits, morse code, changing the order of the nibbles (sorta “endianess” on bytes). Only after a good nap I’ve spotted that the LSB is always 0. In fact every 8th signal in the whole recording is 0. You know what is also always 0? The MSB in the ASCII range. Just reverse the bits and you’ll get F, r, e which, taking into account the nature of this mission, may be the beginning of the word “Frequency”. We’re home.

Solution

The solution is in GO again. The hardest part has been to find the frequency played each second. I tried playing with the Fast Fourier Transform but having no clue about signal processing, I’ve failed miserably. As the whole thing is below 60 lines, I can post it here:

package main

import (
	"fmt"
	"os"

	"sync"

	"github.com/mjibson/go-dsp/wav"
	"github.com/r9y9/gossp/f0"
)

const samplingFreq = 44100

func main() {
	if len(os.Args) < 2 {
		panic("Gimme a *.wav file!")
	}

	testWav, err := os.Open(os.Args[1])
	if err != nil {
		panic(err)
	}
	wr, err := wav.New(testWav)
	if err != nil {
		panic(err)
	}

	samples := make([][]float64, wr.Samples/samplingFreq)

	for sec := range samples {
		s, _ := wr.ReadFloats(samplingFreq)
		samples[sec] = make([]float64, len(s))
		for i, v := range s {
			samples[sec][i] = float64(v)
		}
	}

	freqs := make([]float64, len(samples))
	var wg sync.WaitGroup
	wg.Add(len(freqs))
	for i, s := range samples {
		go func(ind int, smpl []float64) { // speed thing up by doing in parallel
			// work with a shorter sample to speed up the computation and improve accuracy by taking a stable slice
			freqs[ind], _ = f0.NewYIN(samplingFreq).ComputeF0(smpl[samplingFreq/4 : samplingFreq/2])
			wg.Done()
		}(i, s)
	}

	codes := make([]byte, len(freqs)/8)
	wg.Wait()
	for i, f := range freqs {
		codes[i/8] |= byte(f/1000.0) << uint(i%8) // bytes are in-order, bits are reversed
	}

	fmt.Println(string(codes))
}

As you can see, I’ve found a library that calculated the fundamental frequencies for me. For the calculations I have used only a quarter of a each seconds because that gave me much better speed and also accuracy – without this hack the frequencies were sometimes waaaay off, screwing the result up.
The most interesting parts are the loops in lines 31, 42 and 52 that read all the samples in, calculate the fundamental frequency for each second, and put the bits in the right order accordingly.

Running this code on the input data reveals the answer:

Frequency Warrior

Advertisements

Gynvael’s mission 006 [en]

This time a mission from an English stream. As usual we have to discover a hidden message. This time we got this.

Now I must admit I had a lot of luck here. Being after technical studies with a lot of maths, that looked just like some vectors. So the first thought was to draw them as if they were points.

Since it’s too much work by hand, I’ve written a piece of terrible c code to do it for me (warning – no error checking):

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

int main(int argc, char** argv) {

    unsigned char buf[25*25];
    memset(buf, 0xff, 25*25);

    FILE* f = fopen(argv[1], "r");
    int x,y;
    while(fscanf(f, "[%d, %d]\n", &x, &y) == 2) {
        buf[25*y + x] = 0x0;
    }
    fclose(f);

    f = fopen("out.data", "w");
    fwrite(buf, 1, 25*25, f);
    fclose(f);

    return 0;
}

When compiled with gcc main.c -o mission006 and run like ./mission006 039e996d075c6ef746d4558fb4bd7f0dfc493198_mission006.data.txt, this will produce a raw bitmap with 8 bits/pixel. The 25*25 comes from a quick inspection of the file – values are exclusively between 0 and 24.
Then I opened it in GIMP, set mode to grey scale and size to 25×25 and saw…

flipped
At which point I grabbed my phone and scanned it. Turns out it encodes:

Mirrored QR? Seriously?!
One thing though. If you know the QR well or if you’re like me and you used the opportunity to do some reading, you’ll notice soon enough that this image is actually flipped horizontally. (Well you could also get a hint from the solution if you’re smarter than me…). It seems that my scanner doesn’t care but to be completely correct one should just flip it in GIMP or change line 12 of the code to say

buf[25*y + 24-x] = 0x0;

instead. Then you’ll get this:

qr

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.