Alok Menghrajani

Previously: security engineer at Square, co-author of HackLang, put the 's' in https at Facebook. Maker of CTFs.


This blog does not use any tracking cookies and does not serve any ads. Enjoy your anonymity; I have no idea who you are, where you came from, and where you are headed to. Let's dream of an Internet from times past.


Home | Contact me | Github | RSS feed | Consulting services | Tools & games

This post is split in multiple parts. Make sure you first read part 1 and part 2.

Understanding how the assembly code works requires reverse engineering it. The first step is to look at the program's control flow. In some cases, the control flow becomes very complex to decipher (e.g. when dynamic dispatches or signals come into play). To understand the control flow, start by tagging instructions which jump (either conditionally or unconditionally).

Thankfully we aren't dealing with anything too complicated. The code is fairly short and hasn't been purposefully obfuscated. Without yet decoding individual instructions, we can tell:

  • We have an infinite loop that starts at 000B and runs until 004C, 0054 or 005A.
  • We have a subroutine that starts at 005D and ends at 007E. This subroutine gets called 4x per iteration of the above infinite loop.
  • The infinite loop contains 3 conditionals. The subroutine has 1.

Knowing this information, we draft the equivalent code in a higher level language:

main() {
  ... some initialization ...
  while (1) {
    ...
    if (some_condition) {
      ...
    }
    ...
    do_something()
    ...
    do_something()
    ...
    do_something()
    ...
    do_something()
    ...
    if (some_condition) {
      continue;
    }
    ...
    if (some_condition) {
      continue;
    }
    ...
  }
}

do_something() {
  if (some_condition) {
    ...
    return;
  }
  ...
  return;
}

The next post will use this structure and convert each individual instruction.