Being said that move instruction is enough to build a complete computer, anyway move on while you can.


Despite being in the end quite easy, this challenge still taught me something new, so here’s a quick and painless write-up.

$ file ./move
move: ELF 32-bit LSB executable, Intel 80386, version 1 (GNU/Linux), statically linked, stripped
$ ./move
Guess a flag: AAAA
Wrong Flag!

As the name of the challenge suggests, the binary is packed with UPX:

$ strings ./move | grep UPX
$Info: This file is packed with the UPX executable packer $
$Id: UPX 3.91 Copyright (C) 1996-2013 the UPX Team. All Rights Reserved. $

I almost fainted at seeing that the unpacked binary contained only mov instructions. A bit of googling lead me to movfuscator:

The M/o/Vfuscator (short ‘o’, sounds like “mobfuscator”) compiles programs into “mov” instructions, and only “mov” instructions. Arithmetic, comparisons, jumps, function calls, and everything else a program needs are all performed through mov operations; there is no self-modifying code, no transport-triggered calculation, and no other form of non-mov cheating.

After spending an hour trying to make some sense out of this strange disassembly, I spotted at .text:080493DB the suspicious instruction mov R2, 41h which suggests that the characters of the flag could be hardcoded in the binary. I quickly run bgrep together with a simple Python script to extract the immediates used in all the instructions of the form mov R2, <immediate>. It turned out that these values form the string ALEXCTF{M0Vfusc4t0r_w0rk5_l1ke_m4g1c} :)


$ upx -d move && mv ./move ./move-unpacked
                       Ultimate Packer for eXecutables
                          Copyright (C) 1996 - 2013
UPX 3.91        Markus Oberhumer, Laszlo Molnar & John Reiser   Sep 30th 2013

        File size         Ratio      Format      Name
   --------------------   ------   -----------   -----------
  10308504 <-   2619128   25.41%  netbsd/elf386  move

Unpacked 1 file.
$ bgrep "C70568200608" ./move-unpacked
./move-unpacked: 000013db
./move-unpacked: 00001dde
./move-unpacked: 000178cc
#!/usr/bin/env python2
offsets = [0x000013db, 0x00001dde, 0x000027e1, 0x000031e4, 0x00003b9c, 0x0000459f, 0x00004fa2, 0x000059a5, 0x00006357, 0x00006d5a, 0x0000775d, 0x00008160, 0x00008b0c, 0x0000950f, 0x00009f12, 0x0000a915, 0x0000b2bb, 0x0000bcbe, 0x0000c6c1, 0x0000d0c4, 0x0000da64, 0x0000e467, 0x0000ee6a, 0x0000f86d, 0x00010207, 0x00010c0a, 0x0001160d, 0x00012010, 0x000129a4, 0x000133a7, 0x00013daa, 0x000147ad, 0x0001513b, 0x00015b3e, 0x00016541, 0x00016f44, 0x000178cc]

with open('./move-unpacked') as f:
    flag = ''
    for offset in offsets:
        # "mov R2, 41h" is "C70568200608"+"41000000" (the immediate starts after the 6th byte) + 0x6)
        flag +=
    print flag