From aldeid
Jump to: navigation, search
You are here:
Matriochka (step 3)


This challenge is the 3rd stage of the Matriochka challenge. It is described as follows:

Can you help me?
Recently, I found an executable binary.
As I'm a true newbie,
Certainly, to solve it, I will have difficulties.
Keep in mind, the first step is quite easy.
Maybe the last one will be quite tricky.
Emulating it could be a good idea.

You must solve step 1 and step 2 first.

The challenge can be downloaded from the following mirror:


MD5 ecb4999fbfddea74ffa5b8bd22bf1a0a
SHA1 c1b306843328d37df2f029e1384a99359ba2a5cf
SHA256 d080cf9ece1d2ad692c8a90befcc74ac23a0e6466bb489504c040ed93a48cb4e


Running the binary

The program seems to expect an argument, a password:

$ ./stage3.bin 
Usage: ./stage3.bin <pass>
$ ./stage3.bin oops
Try again!

Main function overview

The main function starting at offset 0x4010F1 is structured as follows:


The program relies on Unix signals for its control flow. This is what we are going to analyze in the next sections.

Checking arguments

First of all, the program checks that an argument is passed to the program. If not, it jumps to the "Usage" section.

.text:00000000004010F1 ; int __cdecl main(int, char **, char **)
.text:00000000004010F1 main            proc near
.text:00000000004010F1 pass            = qword ptr -20h
.text:00000000004010F1 num_args        = dword ptr -14h
.text:00000000004010F1 count_i         = dword ptr -8
.text:00000000004010F1 pid             = dword ptr -4
.text:00000000004010F1                 push    rbp
.text:00000000004010F2                 mov     rbp, rsp
.text:00000000004010F5                 sub     rsp, 20h
.text:00000000004010F9                 mov     [rbp+num_args], edi
.text:00000000004010FC                 mov     [rbp+pass], rsi
.text:0000000000401100                 cmp     [rbp+num_args], 2
.text:0000000000401104                 jz      short loc_401121
.text:0000000000401106                 mov     rax, [rbp+pass]
.text:000000000040110A                 mov     rax, [rax]
.text:000000000040110D                 mov     rsi, rax
.text:0000000000401110                 mov     edi, offset format ; "Usage: %s <pass>\n"
.text:0000000000401115                 mov     eax, 0
.text:000000000040111A                 call    _printf
.text:000000000040111F                 jmp     short locret_40119D

Unix signals


Starting at offset 0x401121, the program calls 2 interesting functions. The 1st one (sub_4007FD) is actually the 1st node of a serie of Unix signals an the 2nd one (sub_401050) is the success message.

.text:0000000000401121 loc_401121:
.text:0000000000401121                 mov     rax, [rbp+pass]
.text:0000000000401125                 add     rax, 8
.text:0000000000401129                 mov     rax, [rax]
.text:000000000040112C                 mov     edx, 3FFh       ; n
.text:0000000000401131                 mov     rsi, rax        ; src
.text:0000000000401134                 mov     edi, offset dest ; dest
.text:0000000000401139                 call    _strncpy
.text:000000000040113E                 mov     eax, 0
.text:0000000000401143                 call    _getpid
.text:0000000000401148                 mov     [rbp+pid], eax
.text:000000000040114B                 mov     esi, offset sub_4007FD ; handler
.text:0000000000401150                 mov     edi, SIGSEGV    ; sig
.text:0000000000401155                 call    _signal
.text:000000000040115A                 mov     esi, offset sub_401050 ; handler
.text:000000000040115F                 mov     edi, SIGFPE     ; sig
.text:0000000000401164                 call    _signal
.text:0000000000401169                 mov     [rbp+count_i], 0
.text:0000000000401170                 jmp     short loc_401185

sub_4007FD (1st character)

As described here, the signal function expects 2 parameters:

  • sig: the signal code. Here, the signal used is SIGFPE (code 0x08), used for Signal Floating-Point Exception (e.g. zero divide or an operation resulting in overflow).
  • func: the function that is called. Here, we can see that this is actually a chain of functions, as follows:

Nuit-du-hack-2016-Matriochka-Step-3-sub 4007FD-chain.png

Now, if we analyze the code of the function, it rather looks complex (combination of imul, sar, sub) to make a computation based on the user input. Using the pseudo-code plugin (press F5) will help much. Here is the code it outputs:

void sub_4007FD()
  signed int v0; // [email protected]

  v0 = 1000 * dest;
  if ( v0 / 68 > 999 && v0 / 68 <= 1000 )
    signal(SIGSEGV, (__sighandler_t)handler);

It becomes easier to understand what is actually done. It checks that the 1st character of the user input is equal to 68 (letter "D"). If the test succeeds, the code jumps to the handler function at offset 0x40085C.

sub_40085C (2nd character)

Once again, the function looks complex to analyze and we can use the pseudo-code plugin to get the following output:

void handler()
  signed int v0; // [email protected]

  v0 = 1000 * byte_6040C1;
  if ( v0 / 105 > 999 && v0 / 105 <= 1000 )
    signal(11, (__sighandler_t)sub_4008C7);

This time, the code checks that the second character of the user input is equal to 105 (letter "i"). If the test is successfull, the code jumps to the next function sub_4008C7.

sub_4008C7 (3rd character)

Same here as previously. Below is the pseudo code:

void sub_4008C7()
  signed int v0; // [email protected]

  v0 = 1000 * byte_6040C2;
  if ( v0 / 100 > 999 && v0 / 100 <= 1000 )
    signal(11, sub_400926);

It checks that the 3rd character is equal to 100 (letter "d"). If successfull, the code jumps to sub_400926.

sub_400926 (4rd character)

Below is the pseudo code:

void sub_400926()
  signed int v0; // [email protected]

  v0 = 1000 * byte_6040C3;
  if ( v0 / 95 > 999 && v0 / 95 <= 1000 )
    signal(11, sub_40098A);

The code checks that the 4th character of the user input is equal to 95 ("_"). If successfull, it then jumps to sub_40098A.

And so on...

The exact same approach can be used to decode all other expected letters of the user input.


Below is the expected letters for each function:

Function Expected value Letter
sub_4007FD 68 D
sub_40085C 105 i
sub_4008C7 100 d
sub_400926 95 _
sub_40098A 121 y
sub_4009E8 111 o
sub_400A4C 117 u
sub_400AB0 95 _
sub_400B14 108 l
sub_400B73 105 i
sub_400BD7 107 k
sub_400C36 101 e
sub_400C95 95 _
sub_400D0C 115 s
sub_400D6B 105 i
sub_400DCF 103 g
sub_400E2E 110 n
sub_400E8D 97 a
sub_400EEC 108 l
sub_400F4B 115 s
sub_400FAA 63 ?

Providing the program with this string leads to another base64 string, which will the next challenge (step4):

$ ./stage3.bin Did_you_like_signals?
Good good! Now let's play a game...

This time, it seems to be a DOS/MBR boot sector:

$ cat stage3.base64 | base64 -d > stage4
$ file stage4 
stage4: DOS/MBR boot sector


blog comments powered by Disqus

Keywords: nuit-du-hack-2016 NDH2K16 challenge reversing