JNE, JNZ and loop in nasm

31 Mar 2013

As mentioned in one of my previous posts, I'm busy with the SLAE32 course by SecurityTube. In module 1-9 Control Instructions we saw how the jump instructions work and how you can use them to make conditional and unconditional jumps. When disassembling the code and stepping through it with gdb, we notice that our jnz (jump not zero) instruction was replaced with jne (jump not equal). In this post I will explain what happened. We will also be looking at an alternative for jumps, namely loops.

First of all let's look at the disassembled code versus the compiled code. Source code:

       push eax
        ; Print hello world using write syscall
        mov eax, 0x4
        mov ebx, 1
        mov ecx, message
        mov edx, mlen
        int 0x80
        pop eax
        dec eax
        jnz PrintHW

Dump of assembler code for function PrintHW:

   0x0804808e <+0>: push   eax
   0x0804808f <+1>: mov    eax,0x4
   0x08048094 <+6>: mov    ebx,0x1
   0x08048099 <+11>:    mov    ecx,0x80490b8
   0x0804809e <+16>:    mov    edx,0xd
   0x080480a3 <+21>:    int    0x80
   0x080480a5 <+23>:    pop    eax
   0x080480a6 <+24>:    dec    eax
=> 0x080480a7 <+25>:    jne    0x804808e <PrintHW>
   0x080480a9 <+27>:    mov    eax,0x1
   0x080480ae <+32>:    mov    ebx,0xa
   0x080480b3 <+37>:    int    0x80

So it's pretty obvious that jnz was replaced by jne. I googled around and finally and found Steve Friedl's Unix Wiz. He made a nice overview of all jumps, he also pointed out that there are synonyms. When referring to the table I noted that both jne and jne had the same opcode. Meaning they use the same machine code representative. They are actually synonyms. They bot jump when the zero flag is set (ZF=0). When disassembling gdb doesn't know if it's jne or jnz which was used by the programmer because both opcodes are the same, so it substitutes it with one of them at random.

loops

There are several types of loops:
  • loop: jump unless ECX is zero
  • loope: loop if equal
  • loopne: loop if not equal
  • loopnz: loop if not zero
  • loopz: loop if zero
Below is the source code we shall be using: and my hook-stop
print/x $eax
print/x $ecx
disassemble $eip+10
info registers eflags
end

loop

Let's first look at the normal loop:

_start:     mov ecx,10
        mov eax,0
myloop:     inc eax
        loop myloop

What will happen is:

  • move 10 into ecx and 0 into eax
  • increase eax by 1
  • Check if ECX is 0, if it's not decrement ECX with 1 and jump to myloop
So in the end EAX should be 10 and ECX should be 0. When ECX reaches 0, we will continue with the program and not jump back to myloop. I traced through it with GDB, here is an excerpt of two loop cycles:

(gdb) nexti
$5 = 0x0
$6 = 0xa
Dump of assembler code for function myloop:
=> 0x0804806a <+0>: inc    eax
   0x0804806b <+1>: loop   0x804806a <myloop>
   0x0804806d <+3>: mov    ecx,0xa
   0x08048072 <+8>: mov    eax,0x1
End of assembler dump.
eflags         0x292    [ AF SF IF ]
0x0804806a in myloop ()
(gdb) nexti
$7 = 0x1
$8 = 0xa
Dump of assembler code for function myloop:
   0x0804806a <+0>: inc    eax
=> 0x0804806b <+1>: loop   0x804806a <myloop>
   0x0804806d <+3>: mov    ecx,0xa
   0x08048072 <+8>: mov    eax,0x1
End of assembler dump.
eflags         0x202    [ IF ]
0x0804806b in myloop ()
(gdb) nexti
$9 = 0x1
$10 = 0x9
Dump of assembler code for function myloop:
=> 0x0804806a <+0>: inc    eax
   0x0804806b <+1>: loop   0x804806a <myloop>
   0x0804806d <+3>: mov    ecx,0xa
   0x08048072 <+8>: mov    eax,0x1
End of assembler dump.
eflags         0x202    [ IF ]
0x0804806a in myloop ()
(gdb) nexti
$11 = 0x2
$12 = 0x9
Dump of assembler code for function myloop:
   0x0804806a <+0>: inc    eax
=> 0x0804806b <+1>: loop   0x804806a <myloop>
   0x0804806d <+3>: mov    ecx,0xa
   0x08048072 <+8>: mov    eax,0x1
End of assembler dump.
eflags         0x202    [ IF ]
0x0804806b in myloop ()
(gdb) nexti
$13 = 0x2
$14 = 0x8
Dump of assembler code for function myloop:
=> 0x0804806a <+0>: inc    eax
   0x0804806b <+1>: loop   0x804806a <myloop>
   0x0804806d <+3>: mov    ecx,0xa
   0x08048072 <+8>: mov    eax,0x1
End of assembler dump.
eflags         0x202    [ IF ]
0x0804806a in myloop ()

Special loops

We also have the special loops loopz and loope, it's important to note that, just like jnz and jne, loope/loopne and loopz/loopnz are synonyms. So they basically they do exactly the same thing. Now the difference between loop and loopz is that loopz will not only look at ECX, but will also look at the zero flag (ZF). If the zero flag is set and ECX does not equal to 0, loopz will jump. loopnz and loopne will jump as long as ECX is not 0 and the ZF is not set. But when does the ZF get set?

  • Arithmetic instructions (sub,add,dec,inc,...)
  • Bitwise operations (or,xor, and,...)
  • Compare instruction like cmp
Now to demonstrate how this works, let's jump to the second section of the code:

        mov ecx,10
        mov eax,1
myloopz:    dec eax
        loopz myloopz

What will happen is:

  • move 10 into ECX and 1 into EAX
  • decrement EAX with 1, the 0 flag will be set
  • loopz => Is ZF set? Yes!, does ECX equal to 0? No! --> Jump to myloopz
  • decrement EAX with 1 (ZF gets unset)
  • loopz => Is ZF set? No!, does ECX equal to 0? No! --> do not jump, proceed with the code
Here is my GDB trace:

(gdb) nexti
$49 = 0x1
$50 = 0xa
Dump of assembler code for function myloopz:
=> 0x08048077 <+0>: dec    eax
   0x08048078 <+1>: loope  0x8048077 <myloopz>
   0x0804807a <+3>: mov    eax,0x1
   0x0804807f <+8>: mov    ebx,0xa
   0x08048084 <+13>:    int    0x80
End of assembler dump.
eflags         0x206    [ PF IF ]
0x08048077 in myloopz ()
(gdb) nexti
$51 = 0x0
$52 = 0xa
Dump of assembler code for function myloopz:
   0x08048077 <+0>: dec    eax
=> 0x08048078 <+1>: loope  0x8048077 <myloopz>
   0x0804807a <+3>: mov    eax,0x1
   0x0804807f <+8>: mov    ebx,0xa
   0x08048084 <+13>:    int    0x80
End of assembler dump.
eflags         0x246    [ PF ZF IF ]
0x08048078 in myloopz ()
(gdb) nexti
$53 = 0x0
$54 = 0x9
Dump of assembler code for function myloopz:
=> 0x08048077 <+0>: dec    eax
   0x08048078 <+1>: loope  0x8048077 <myloopz>
   0x0804807a <+3>: mov    eax,0x1
   0x0804807f <+8>: mov    ebx,0xa
   0x08048084 <+13>:    int    0x80
End of assembler dump.
eflags         0x246    [ PF ZF IF ]
0x08048077 in myloopz ()
(gdb) nexti
$55 = 0xffffffff
$56 = 0x9
Dump of assembler code for function myloopz:
   0x08048077 <+0>: dec    eax
=> 0x08048078 <+1>: loope  0x8048077 <myloopz>
   0x0804807a <+3>: mov    eax,0x1
   0x0804807f <+8>: mov    ebx,0xa
   0x08048084 <+13>:    int    0x80
End of assembler dump.
eflags         0x296    [ PF AF SF IF ]
0x08048078 in myloopz ()
(gdb) nexti
$57 = 0xffffffff
$58 = 0x8
Dump of assembler code for function myloopz:
   0x08048077 <+0>: dec    eax
   0x08048078 <+1>: loope  0x8048077 <myloopz>
=> 0x0804807a <+3>: mov    eax,0x1
   0x0804807f <+8>: mov    ebx,0xa
   0x08048084 <+13>:    int    0x80
End of assembler dump.

And that's how it works. I was thinking of adding the solution to the exercise, but that would be spoiling it ;)