Secure coding

Conditionals and jump instructions in x86

Srinivas
March 25, 2020 by
Srinivas

This article will briefly discuss conditionals and jump instructions. Conditionals are commonly used in assembly for comparison so that other instructions can make use of the output resulting from these. Jump instructions in assembly are a way to permanently transfer the execution to another instruction located at a different memory address. 

Let us explore how all these concepts fit together in assembly, specifically x86.

Intro to x86 Disassembly

Intro to x86 Disassembly

Build your x86 assembly skills with six courses covering the basics of computer architecture, how to build and debug x86, x86 assembly instructions and more.

What are conditionals?

Making a decision based on the result of a comparison operation is possible in any programming language. Assembly is no different, and it is possible to make comparisons and make decisions based on the comparisons in assembly language too. 

TEST and CMP are the instructions that are commonly used for comparison in x86, and these instructions are known as conditionals.

TEST instruction

The TEST instruction computes the bitwise logical AND of first operand and the second operand. According to the result, the status flags SF, ZF and PF will be set.

 It should be noted that the TEST instruction doesn't make any changes to the operands used with the instruction. The following is an example of a TEST instruction.

Example: TEST EAX, EAX

CMP instruction

The CMP instruction is another example of conditionals. A CMP instruction performs a subtract operation on both operands, and the status flags ZF and CF will be set according to the result. 

It should be noted that the CMP instruction also does not affect the operands. When the destination operand and source operand are equal, ZF will be set to 1. If the destination operand is less than the source operand, CF will be set to 1. In all the remaining conditions, the respective flags will be set to 0. 

Following is an example of CMP instruction.

Example: CMP EAX, 1

Let’s see an example of both TEST and CMP instructions. The following code is an excerpt from the disassembly of a compiled C binary.

MOV EAX,DWORD PTR DS:[4053E4]

XOR EBX,EBX

CMP EAX,1

JE function.004013E3

MOV EAX,DWORD PTR DS:[4053E4]

TEST EAX,EAX

This excerpt has both CMP and TEST instructions. We can observe the results of these two instructions by setting a breakpoint on them.

Before executing CMP EAX, 1, the following is the status of the EAX register and the status flags:

EAX 00000000

C 0  ES 002B 32bit 0(FFFFFFFF)

P 1  CS 0023 32bit 0(FFFFFFFF)

A 0  SS 002B 32bit 0(FFFFFFFF)

Z 1  DS 002B 32bit 0(FFFFFFFF)

S 0  FS 0053 32bit 2D2000(FFF)

T 0  GS 002B 32bit 0(FFFFFFFF)

D 0

O 0  LastErr ERROR_FILE_NOT_FOUND (00000002)

After stepping through the CMP instruction, the following is the status of the EAX register and the status flags.

EAX 00000000

C 1  ES 002B 32bit 0(FFFFFFFF)

P 1  CS 0023 32bit 0(FFFFFFFF)

A 1  SS 002B 32bit 0(FFFFFFFF)

Z 0  DS 002B 32bit 0(FFFFFFFF)

S 1  FS 0053 32bit 2D2000(FFF)

T 0  GS 002B 32bit 0(FFFFFFFF)

D 0

O 0  LastErr ERROR_FILE_NOT_FOUND (00000002)

As we can observe in both the excerpts, there is no difference in the value of EAX before and after the execution of the CMP instruction. But the only change we see is in the status flag registers. Now, let’s do single steps until we hit the next breakpoint, where TEST instruction is located. 

Before executing the TEST EAX, EAX instruction, the following is the status of the EAX register and the status flags.

EAX 00000000

C 1  ES 002B 32bit 0(FFFFFFFF)

P 1  CS 0023 32bit 0(FFFFFFFF)

A 1  SS 002B 32bit 0(FFFFFFFF)

Z 0  DS 002B 32bit 0(FFFFFFFF)

S 1  FS 0053 32bit 2D2000(FFF)

T 0  GS 002B 32bit 0(FFFFFFFF)

D 0

O 0  LastErr ERROR_FILE_NOT_FOUND (00000002)

Let’s do a single step. The following is the status of the EAX register and the status flags after stepping through the TEST instruction.

EAX 00000000

C 0  ES 002B 32bit 0(FFFFFFFF)

P 1  CS 0023 32bit 0(FFFFFFFF)

A 0  SS 002B 32bit 0(FFFFFFFF)

Z 1  DS 002B 32bit 0(FFFFFFFF)

S 0  FS 0053 32bit 2D2000(FFF)

T 0  GS 002B 32bit 0(FFFFFFFF)

D 0

O 0  LastErr ERROR_FILE_NOT_FOUND (00000002)

As we can observe in both the excerpts, once again there is no difference in the value of EAX before and after the execution of CMP instruction. But the only change we see is in the status flag SF. 

Introduction to JUMP instructions

Jump instructions in assembly are used for branching, which describes the control flow of the program. There are two popular types of jump instructions: unconditional jump and conditional jump.

Unconditional jump

Unconditional jumps are the simplest form of jump instructions. As the name suggests, the execution will always flow to the target location specified. Following is the syntax of an unconditional jump instruction.

JMP <target location>

Conditional jump

Conditional jumps are used to take jumps based on the value of status flags. Conditional jumps are commonly used when concepts like IF statements and loops are needed to be used in Assembly. Because assembly language doesn't support statements like if statements, conditional jumps are used to determine whether to take a jump or not. 

There are more than 30 different conditional jump instructions, but following are some commonly used ones:

JZ — Jump if Zero; checks for ZF = 1

JE — Jump if Equal; checks for ZF = 1

JNZ — Jump if Not Zero; checks for ZF = 0

JNE — Jump if Not Equal; checks for ZF = 0

JC — Jump if Carry; checks for CF = 1

JNC — Jump if No Carry; checks for CF = 0

JS — Jump if Signed (Negative); checks for SF = 1

JG — Jump if Greater

JNLE — Jump if Not Less or Equal

JGE — Jump if Greater or Equal

JNL — Jump if Not Less

JL — Jump if Less

JLE — Jump if Less or Equal

JNG — Jump if Not Greater

The following example shows how jump instructions work.

PUSH EBP

MOV EBP,ESP

AND ESP,FFFFFFF0

SUB ESP,20

CALL if.004015F0

MOV DWORD PTR SS:[ESP+1C],1E

MOV DWORD PTR SS:[ESP+18],14         

MOV EAX,DWORD PTR SS:[ESP+1C]       

CMP EAX,DWORD PTR SS:[ESP+18]       

JLE SHORT if.00401546                

MOV DWORD PTR SS:[ESP],if.00404000   ; |ASCII "a is greater than b"

CALL <JMP.&msvcrt.puts>    

JMP SHORT if.00401552

MOV DWORD PTR SS:[ESP],if.00404014   ; |ASCII "b is greater than a"

CALL <JMP.&msvcrt.puts>     NOP

LEAVE

RETN

The preceding excerpt is a simple example of how both unconditional and conditional jumps work. In this example, JLE is a conditional jump instruction and JMP SHORT <TARGET> is an unconditional jump instruction. Let’s set breakpoints on both JLE and JMP instructions and understand how they work.

Conditional jumps usually depend on the results of other instructions like CMP. In this case, the following is the status of the status flags after the CMP instruction is executed.

C 0  ES 002B 32bit 0(FFFFFFFF)

P 1  CS 0023 32bit 0(FFFFFFFF)

A 0  SS 002B 32bit 0(FFFFFFFF)

Z 0  DS 002B 32bit 0(FFFFFFFF)

S 0  FS 0053 32bit 249000(FFF)

T 0  GS 002B 32bit 0(FFFFFFFF)

D 0

O 0  LastErr ERROR_SUCCESS (00000000)

A JLE instruction usually checks for the flags O, S and Z. In our case, none of these flags are set by a CMP instruction. Thus, a conditional jump will not be taken and the next instruction will be executed. 

When JMP instruction is executed, it will not look for any dependencies and the jump will always be taken to the target address specified in the JMP instruction.

Conclusion

In this article, we explored the concepts of conditionals and jump instructions. We used various examples with sample instructions to better understand these concepts. 

We showed that conditionals are used for comparisons and jump instructions are used for changing the execution flow. It was also understood that unconditional jump instructions will always take jumps and conditional jump instructions rely on the output of other instructions such as CMP.

Intro to x86 Disassembly

Intro to x86 Disassembly

Build your x86 assembly skills with six courses covering the basics of computer architecture, how to build and debug x86, x86 assembly instructions and more.

Sources

  • Randal Hyde, “The Art of Assembly Language,” No Starch Press, March 2010
  • Michael Sikorski and Andrew Honig, “Practical Malware Analysis,” No Starch Press, February 2012
  • Reverse Engineering for Beginners, Dennis Yurichev
Srinivas
Srinivas

Srinivas is an Information Security professional with 4 years of industry experience in Web, Mobile and Infrastructure Penetration Testing. He is currently a security researcher at Infosec Institute Inc. He holds Offensive Security Certified Professional(OSCP) Certification. He blogs atwww.androidpentesting.com. Email: srini0x00@gmail.com