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

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. This excerpt has both CMP and TEST instructions. We can observe the results of these two instructions by setting a breakpoint on them. CMP EAX,1 JE function.004013E3 MOV EAX,DWORD PTR DS:[4053E4] TEST EAX,EAX Before executing CMP EAX, 1, the following is the status of the EAX register and the status flags: After stepping through the CMP instruction, the following is the status of the EAX register and the status flags. 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, 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.  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) Before executing the TEST EAX, EAX instruction, the following is the status of the EAX register and the status flags. 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. 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, 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.  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)

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

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: The following example shows how jump instructions work. 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 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 is an unconditional jump instruction. Let’s set breakpoints on both JLE and JMP instructions and understand how they work. 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 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. 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.  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) 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.

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