Introduction

Branching out in multiple ways, the switch statement appropriately dispenses execution to parts of code, based on the expression’s value. A switch statement is a code construct that is used in programming to make a decision, based on a character or integer. Lengthy “if” statements that compare integral values against a variable are often replaced by a switch statements. 

When reverse-engineering a malicious binary, being able to identify switch statements can be useful when dealing with most malware classes. For instance, a malware with keylogger functionality most likely uses a switch statement for switching through special keys such as SHIFT in the keyboard. 

In this article, we will discuss how switch statements can be spotted when reversing a binary.

Switch statements

Figure 1 shows a code snippet of how switch statements are used in the C programming language. 

 

#include <stdio.h>

void main()

{

int i = 3;

switch(i)

{

case 1: printf(“Value is 1\n”);

        break;

case 2: printf(“Value is 2\n”);

        break;

case 3: printf(“Value is 3\n”);

        break;

default: printf(“Value out of range\n”);

       

}

}

Figure 1

 

The integer variable named “i” was declared and initialized with value 3 to keep the example simple. This value passes to a switch statement. Then the statements inside the matching case will be executed. The text “Value is 3” will be printed when this code is compiled and run. 

When the Figure 1 code is compiled and the binary is opened using a debugger (OllyDbg in this case), the following results.

 

PUSH EBP

MOV EBP,ESP

AND ESP,FFFFFFF0

SUB ESP,20

CALL switch.00401610

MOV DWORD PTR SS:[ESP+1C],3          ; |

CMP DWORD PTR SS:[ESP+1C],2          ; |

JE SHORT switch.00401549             ; |

CMP DWORD PTR SS:[ESP+1C],3          ; |

JE SHORT switch.00401557             ; |

CMP DWORD PTR SS:[ESP+1C],1          ; |

JNZ SHORT switch.00401565            ; |

MOV DWORD PTR SS:[ESP],switch.00404000   ; |ASCII “Value is 1”

CALL <JMP.&msvcrt.puts>              ; \puts

JMP SHORT switch.00401571

MOV DWORD PTR SS:[ESP],switch.0040400B   ; |ASCII “Value is 2”

CALL <JMP.&msvcrt.puts>              ; \puts

JMP SHORT switch.00401571

MOV DWORD PTR SS:[ESP],switch.00404016   ; |ASCII “Value is 3”

CALL <JMP.&msvcrt.puts>              ; \puts

JMP SHORT switch.00401571

MOV DWORD PTR SS:[ESP],switch.00404021   ; |ASCII “Value out of range”

CALL <JMP.&msvcrt.puts>              ; \puts

NOP

LEAVE

RETN

Figure 2

 

Figure 2 shows how the switch statement works in assembly. First, the following instruction is used to initialize the local variable “i” by pushing its value onto the stack. 

 

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

Figure 3

 

Figure 4 shows the stack after the Figure 3 instruction is executed. 

 

Figure 4

 

As we can see, the value 3 is pushed onto the stack and it is referenced by [ESP+1C]. 1C in hex translates to decimal value 28. This value 3 will be used to check against the case values in the next few instructions, as shown below.

 

CMP DWORD PTR SS:[ESP+1C],2           

JE SHORT switch.00401549     

Figure 5

 

Figure 5 shows a comparison is done using the value pushed onto the stack against the case value 2. If both these values are equal, JE will take a jump. The values are not the same and the jump will not be taken. The next instructions will be executed, as shown in Figure 6..

 

CMP DWORD PTR SS:[ESP+1C],3           

JE SHORT switch.00401557            

Figure 6

 

The comparison is done against case value 3 and the values being compared will be equal. The zero flag will be set to 1 after the CMP instruction is executed. This is shown in Figure 7.

 

Figure 7

 

Since the zero flag is set to 1, the JE instruction will take the jump and case 3 will be executed, as shown in Figure 8.

 

MOV DWORD PTR SS:[ESP],switch.00404016   ; |ASCII “Value is 3”

CALL <JMP.&msvcrt.puts>              ; \puts

Figure 8

 

Figure 9 

(Note: This is an overview of assembly instructions and their respective addresses)

Conclusion

Identifying switch statements is important when analyzing executables because they allow a value to transfer control of execution. However, code with switch statements produce multiple CMP and JXX instructions which may look like a sequence of “if” statements. Identifying these instructions as switch is difficult without access to the source code. Using a debugger like OllyDbg is helpful in making this determination by offering the assembly code where source code is unavailable.

 

Sources

  1. x86 instruction set reference, c9x.me
  2. Michael Sikorski and Andrew Honig, “Practical Malware Analysis: The Hands-On Guide to Dissecting Malicious Software,” No Starch Press, February 2012

Be Safe

Section Guide

Srinivas

View more articles from Srinivas

As you grow in your cybersecurity career, Infosec Skills is the platform to ensure your skills are scaled to outsmart the latest cyber threats.

Section Guide

Srinivas

View more articles from Srinivas