We got two files with the challenge:
meow.n
, runningfile
command on it said:NekoVM bytecode (418 global symbols, 323 global fields, 35212 bytecode ops)
flag_enc.png
which was a seemingly encrypted PNG image:
I googled NekoVM
which lead me to https://nekovm.org/ which said:
Neko is a high-level dynamically typed programming language. It can be used as an embedded scripting language. It has been designed to provide a common runtime for several different languages. Learning and using Neko is very easy. You can easily extend the language with C libraries. You can also write generators from your own language to Neko and then use the Neko Runtime to compile, run, and access existing libraries.
Okay, something, something, yet again some unknown byte code. I googled for disassembler, but it turned out the official toolchain includes one: https://nekovm.org/doc/tools/#dumping-bytecode , so I run
nekoc -d meow.n
and I got a 620k meow.dump
file. Uhh, that’s a lot of code. I searched for xor
in the dump as I usually do if I start working with a lot of code, and I found a few interesting strings around the xoring code lines like get_pixel
, set_pixel
, setSeed
, random_set_seed
, file_open
, file_read
, AccInt 13337
.
I also found some usage information: Usage: meow INPUT OUTPUT
.
As the bytecode was new to me, I googled some description on what these “operators” mean, and I found this Neko Bytecode Explained page which would be a really good resource I think.
BUT I thought: okay, so it reads a PNG and generates some random, uses some magic seeds and contants like 13337
and writes an another PNG. I could probably find out the exact algorithm from the byte code statically but that would take ages, so let’s analyze it dynamically instead.
So I encrypted a full black and white 768x768 PNG (just like the original). Actually I did it both twice and got the exact same result (for the same color), and I got the inverse for the other, so I could be sure that the algorithm kind of static and there is no random stored in the encrypted file.
Black
was encrypted to
White
was encrypted to
Flag (first try)
Okay, the result was similar to our encrypted flag, so I simply xored the black_enc.png
with flag_enc.png
and I got this:
Wow that is almost a readable flag
, but it looks like the columns were mixed.
Then I encrypted images with unique columns and decrypted with my method and result seemed consistent:
Color
was encrypted to
Unique colors
was encrypted to
Flag (final)
So I simply tried to reorganize the columns in the same order as it changed on my test file and I got the original image with the flag actually:
So the flag was:
And this was my solver code (C#):