Debugging an application means to detect and remove bugs from an application. Debuggers are essential in software programming because they can help quickly identify a syntactic or logic error in a program. In the field of malware analysis, debuggers are used to study how malicious codes work in order to provide a method of detection and removal. Debuggers are also used by software pirates who reverse engineer popular software to find ways to remove protections put in place by the application developers. Due to the emergence of software pirates and their utilization of debuggers, developers use anti-debugging techniques to serve as a deterrence to those individuals who reverse engineer their code. There is no complete solution to stop a reverse engineer who is committed, however, anti-debugging techniques makes the process more difficult, requires a higher level of expertise to bypass, and increases the time for analysis of an application .Similar to application developers, who utilize anti-debugging techniques to serve as a layer of protection for their software, malware authors also adopt these techniques for the malware they create. In this scenario debugging techniques serve as a deterrence to malware analysts. The purpose is to prevent accurate analysis of the malicious code by the malware analysts and in effect increase the lifespan of the malware.
2. Dynamic Behavior of Int2d
Many anti-debugging techniques exist; however, this section concentrates on the Int2d instruction since it is frequently used in the Max++ rootkit. The int2d interrupt is a special interrupt reserved for Microsoft kernel debugging service. It raises an exception to be handled by the kernel debugger. If the kernel debugger does not handle the exception it is then passed to the user level exception handling. When an interrupt 2d is executed, the memory address of the exception points to the EIP register. The EIP register is the instruction pointer and always points to the next instruction. After the exception address has been set to the EIP register, the EIP is incremented by one byte. An exception breakpoint is issued and the exception is either handled or not handled by an exception handler. When no debugger is attached to the system, execution will resume at the address of the exception. The execution will resume normally because the exception is assumed to be corrected and the process can continue from the exception address. If a debugger is present, the execution of the program will continue at the EIP address which is one byte after the exception address. The program skips one byte and this is known as a byte scission.
Due to the difference in observed behavior of the int2d instruction, this can be used to determine if a debugger is present on the system. Also since one byte is skipped, this instruction can be used to change the execution of programs based on the debugging environment. A program may run differently if a debugger is attached to the system as opposed to if no debugger is attached. This technique proves problematic for malware analysis.
This section also explores the dynamic nature of the int2d instruction. The complexities of int2d are more than meets the eye and the factors that change its behavior are numerous. Some examples of factors that can change the observed behavior of the int2d instruction are the values of the register, the structured exception handling, whether a user level debugger is present, as well as whether a kernel level debugger is attached. Different behaviors can be observed by combinations of the above examples. An experimental approach is followed to examine the change in behavior exhibited by int2d.
3. Int2d Experiment Design
To analyze the int2d instruction, the C program in Figure 2.2 is utilized. Written by Dr. Xiang Fu , the Int2dExp.cc program is used in this paper to perform experiments with the int2d instruction. The file is compiled into a binary executable to later debug. The program consists of two print statements. The first print statement displays the characters “AAAA”. The second print statement displays the characters “BBBB”. Variables are also included in the code to give room to insert assembly instructions in a debugger. Immunity debugger allows us to debug the executable and modify the assembly instructions.
|Figure 2.2 – C code for Int2dExp.cc|
Figure 2.3 shows the int2dexp binary file opened in Immunity debugger. The important section of the assembly instructions are shown below. From the memory address “004010DA” to “004010EF, the variables “a” through “d” are initialized. The next two lines stores the value “AAAA” and display it by calling the “printf” function from the “cygwin.dll” file at address “004010FD”. The second print statement is located at address “00401125” and displays the characters “BBBB”.
|Figure 2.3 – Assembly instructions shown in Immunity debugger for int2dexp executable|
The instructions are modified to incorporate the use of the int2d instruction. In order to test the different behaviors we set up an int2d instruction and overwrite the previous initialization of variables. The int2d is followed by a one byte instruction which is “INC”. To test if the byte after int2d is skipped we include a “CMP” and “JE” instruction. “CMP” compares two values and sets the Z flag in the debugger. The instruction compare subtracts the two values from each other and if they are equal then the result is zero. When the result is zero the “Z flag”, which stands for “zero flag”, will be set to one. If the two values in the compare instruction are not equal the z flag is set to zero. The “JE” instruction stand for “jump if equal to zero” and it depends on the “z flag”. If the two values in the compare function are equal, then the z flag is set to 1 and the “JE” is true and results in a jump to the address specified. The “JE” instruction allows us to see if int2d causes a byte scission. Figure 2.4 shows the modified int2dexp with the EAX register set to one. If a byte is skipped then the “INC EAX” instruction will not be executed. The EAX register retains the same value and at the instruction “CMP” the two values remain equal. The jump instruction is true and the execution would jump from the address “0040110D” to “0040112A”. The jump address is right after the second print statement and prevents the characters “BBBB” from being displayed. Figure 2.4 only displays the character “AAAA”.
|Figure 2.4 - Assembly instructions in Immunity debugger for int2dexp where EAX equals one and the JE is included|
Another way to accomplish the same experiment above is to replace the instruction “JE” with the instruction “JNZ”. “JNZ” stand for jump if not equal to zero and does the exact opposite of the “JE” instruction. If two values in the compare function are not equal to each other than the JNZ instruction will jump to a specified address. For the same example above if we replace JE with JNZ the program would display “AAAABBBB” instead of only “AAAA”. “JNZ” example can be seen in Figure 2.5.
|Figure 2.5 – Assembly instructions in Immunity debugger for int2dexp where EAX equals one and JNZ is included|
The program above allows us to test the int2d behavior against two factors. First the debugging environment is changed. The execution is examined with a user level debugger attached, a kernel level debugger attached, and with no debugger attached. The second factor that is changed is the value of the EAX register. The EAX register can be easily modified by changing the value at address “00401102”. Figure 2.6 shows an example where the EAX register is changed to the value two.
|Figure 2.6 - Assembly instructions in Immunity debugger for int2dexp where EAX equals two and JE is included|
4. Int2d Experiment Configuration
A virtual box image of Windows XP SP2 was used as a host system. The guest system was Windows 7 Home Edition with debugger tools installed on both systems. Below is the serial port configuration for the host system.
|Figure 2.7 – Serial port configuration for the windows host system|
Figure 2.7 displays the command issued to start a windbg session through the windows SDK command prompt. The port must match the virtual box serial configuration shown above.
|Figure 2.8 – Windows SDK 7.1 Command prompt and command to connect to host system|
A successful connection to the host machine presents the following window shown below in Figure 2.6. Windbg executes an interrupt “int 3” on the machine by default when first connected and the command “g”, which stands for go, resumes the execution of the host system.
|Figure 2.9 – A successful connection established in WinDbg|
This command is also used to continue execution of the host machine when an exception has been raised and the host system waits for the exception to be handled. This command is used in the following experiments.
5. Int2d Experiment Results
Figure 2.8 presents results for the experiments with the int2d instruction. The values 1, 2, 3, 4, and 99 are used for the register EAX. Also the int2dprint program executes in different debugging environments and the different combinations are listed below.
|Figure 2.10 - Results for executing int2dexp.exe in various debugging environments and with different values for the |
One particular area of interest is the row where the EAX register value is one and the different debugging environments are tested. Red text indicates that the “INC” instruction executed and the int2d did not cause a byte to be skipped. This behavior is observed only when a kernel debugger is attached to the system, in this case windbg. When windbg is not attached to the system and the EAX register value is one, the int2d interrupt does cause a byte to be skipped. This is significant due to the fact different behaviors are observed and can be used to determine when a debugger is attached and when it is not attached.
From the figure above we can see there is a way to precisely identify if the system is set up in one of four configurations. One configuration is a kernel debugger and a user level debugger attached to a system. The second configuration is a kernel debugger and no user level debugger attached. The third configuration is no kernel debugger and a user level debugger attached. The last configuration is no kernel debugger and no user level debugger attached. Each of the configurations can be identify by their unique behavior.
The configuration of no kernel debugger and no user level debugger can be identified when EAX is equal to zero. Figure 2.10 shows that only in this set up, where the EAX is equal to zero, the “int2dprint” program displays no characters in the command window.
The configuration of no kernel debugger and immunity debugger can be identified when the EAX is equal to two. When the EAX is equal to two, this is the only set up where the output of “int2dprint”is “AAAA” for the “JZ0” command and “AAAABBBB” for the “JNZ” command. Two other configurations also print the same statements, however, only after the WinDbg breakpoint is resumed by the guest system.
The third configuration of kernel debugger and no user level debugger attached can be identified when the EAX register is equal to zero. Only in this set up the “INC EAX” is executed and the resulting display is “AAAABBBB” for the “JZ0” command and “AAAA” for the “JNZ” command.
The last configuration of kernel debugger and user level debugger can also be identified but in two steps. When EAX is equal to zero, there is one configuration that shares the same result where there is a kernel debugger and user level debugger attached to the system. The second configuration that shares the same result for the “int2dprint” is where there is no kernel debugger and a user level debugger is attached. For both of these set ups the result of the program is “AAAA” for the “JZ0” command and “AAAABBBB” for the “JNZ” command. The configuration of kernel debugger and user level debugger attached can be determined by checking the EAX value of two after the EAX value of zero. If the output is not “AAAA” for “JZ0” when the EAX value is equal to two, then the configuration we have is a kernel debugger and user level debugger attached. Alternately, process of elimination can be used since three of the four configurations can be identified.
Here lies the reason the int2d instruction serves as an anti-debugging technique. A program with an int2d interrupt can cause a program to execute differently with a debugger attached as opposed to without a debugger. As shown above with Immunity debugger, when EAX equals one, “AAAABBBB” printed with a debugger was attached. “AAAA” printed with no debugger was attached. Malware authors use this interrupt to prevent accurate analysis of their malware.
An important note to make is that int2d can be used to crash a system. As shown in Figure 2.10, when the EAX register is equal to zero, and the computer is in debug mode, and immunity debugger is not attached, if the int2d instruction is used then the system will freeze and require a manual reboot. Also a system can be crashed with immunity debugger attached. If the EAX register is changed to two and the int2d is executed, again the system freezes and requires a manual reboot.
 Dr. Xiang Fu, Malware Analysis Tutorial 4: Int2dh Anti-Debugging, Available at