LabyREnth Challenge Two

Synopsis - BabbySay What?

Here is the second LabyREnth challenge which launches a virtual piano. Guessing a particular set of keys must be played to see the secret.

LabyREnth Challenge Two - Piano

I originally solved this using JetBrain's DotPeek[1] w/ Visual Studio. This walk-though will make use of dnSpy[2] instead as a way to compare my experiences between the two tools.


Binary Analysis

The first thing we need to do is determine what type of binary this is. Upon loading it into CFF Explorer it appears to be a 32 bit .NET executable.

LabyREnth Challenge Two - File Info

Now we know which tool to proceed with.


For .NET executables, it is relatively easy to decompile the binary to get the source (with the right tool that is). Enter dnSpy! Upon loading the binary into dnSpy, we can browse the source code, set breakpoints, modify the code, and run it in debug mode. So let's do some static analysis.

The entry point for .NET executables is under Program Main().

LabyREnth Challenge Two - SRC 1

Main creates a new instance of Form1 and make it visible. Let's look at Form1. As the input appears to be from the virtual "keys", let's look for the corresponding click event(s). Checking the constructor, they are configured there at lines 53 (black) and again at 70 (ivory).

LabyREnth Challenge Two - SRC 2

Clicking on key_click takes us to the function and pay dirt! Taking a look at the function, we see the series of keys and the order they must be clicked in.

119: if (keyButton.number == 16 && keyButton.is_black && this.dat_state == 0)

135: if (keyButton.number == 24 && !keyButton.is_black && this.dat_state == 1)

151: if (keyButton.number == 25 && !keyButton.is_black && this.dat_state == 2)

176: if (keyButton.number == 21 && !keyButton.is_black && this.dat_state == 3)

183: if (keyButton.number == 16 && keyButton.is_black && this.dat_state == 4)

199: if (keyButton.number == 24 && !keyButton.is_black && this.dat_state == 5)

215: if (keyButton.number == 25 && !keyButton.is_black && this.dat_state == 6)

231: if (keyButton.number == 21 && !keyButton.is_black && this.dat_state == 7)


  1. Black : 16
  • White : 24
  • White : 25
  • White : 21
  • Black : 16
  • White : 24
  • White : 25
  • White : 21

Sing, Piano. Sing!

Time to play. I'm guessing that it's the key at index 16 from the left (versus the 16th key). Let's test this. Set a breakpoint on line 119 and click on the 17th black key from the left and check the value of keyButton.number (or just single step and see if the condition evaluates to true).

LabyREnth Challenge Two - Evaluate Key 16

Looking at the value (interrogate the sender parameter) it reads 0x10 (16), thus our hunch was correct.

Now let's play! Voola! There's the key scrolling by... and a distracting video.

LabyREnth Challenge Two - Key Video

Let's remove the video to make it easier to read the key.

Edit the file and delete or comment out the following lines:

LabyREnth Challenge Two - CommentOut

Click compile (had to remove a line it was complaining about to get it to compile but it should not adversely effect the program) and it now reads:

LabyREnth Challenge Two - ApplyChanges

Don't forget Crtl+Shift+S to save before running it again or the change will not show.

Run the program and play the not so secret combination and you'll get:

LabyREnth Challenge Two - NoVid

Read as it scrolls by to get the key (can be tricky to discern 0 from O):


And done!


Overall straight forward, but then again I'm fairly comfortable with .NET. dnSpy worked great just like the combination of dotPeek and VS. Navigation, of course, was different and finding the value of a variable at debug time was not a simple mouse cursor over the variable like in VS but I was able to find it in the Locals panel easily enough.

  1. DotPeek ↩︎

  2. dnspy ↩︎

comments powered by Disqus