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 9vUPX! $Info: This file is packed with the UPX executable packer http://upx.sf.net $ $Id: UPX 3.91 Copyright (C) 1996-2013 the UPX Team. All Rights Reserved. $ UPX!u UPX! UPX!
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
$ 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) f.seek(offset + 0x6) flag += f.read(1) print flag