ZeroAccess: int 2d Anti-Debugging
The general anti-debugging techniques are as follows:
(1) to detect the existence of a debugger, and behave differently when a debugger is attached to the current process; and,
(2) to disrupt or crash a debugger.
The instruction we are trying to analyze is the "INT 2D" instruction located at 0x00413BD5 (as shown in Figure 1). By single-stepping the malware, you might notice that the program's entry point is 0x00413BC8. After the execution of the first 8 instructions, right before the "INT 2D" instruction, the value of EAX is 0x1. This is an important fact you should remember in the later analysis.
Now let us watch the behavior of the Immunity Debugger (IMM). By stepping over (using F8) the instruction "INT 2D" at 0x413BD5, we are supposed to stop at the next immediate instruction "RETN" (0x00413BD7), however, it is not. The new EIP value (i.e., the location of the next instruction to be executed is 0x00413A38)! Now the big question: is the behavior of the IMM debugger correct (i.e., is it exactly the same as the normal execution of Max++ without debugger attached)?
When a program uses instructions like "int 2d" - it's an exception and triggers a whole procedure of interrupt handling. It is beneficial to completely understand the technical details involved in the interrupt handling scenario. We recommend the Intel IA32 Manual  (ch6: interrupt and exception overview). Some important facts are listed below:
NTSTATUS DebugService(UCHAR ServiceClass, PVOID arg1, PVOID arg2)
According to , there are four classes (1: Debug printing, 2: interactive prompt, 3: load image, 4: unload image). The call of DebugService is essentially translated to the following machine code:
EAX <- ServiceClass
ECX <- Arg1
EDX <- Arg2
The interrupt triggers CPU to jump to KiDispatchException, which later calls KdpTrap (when the DEBUG mode of the windows ini file is on, when Windows XP boots). KdpTrap takes an EXCEPTION_RECORD constructed by KiDispatchException. The EXCEPTION_RECORD contains the following information: ExceptionCode:BREAKPOINT, arg0: EAX, arg1: ECX, and arg2: EDX. Note that according to  (Section "Notifying Debugging Events"), the INT 3 interrupts (software breakpoints) is also handled by KdpTrap except that arg0 is 0.
Notice that KiDispatchException deserves some special attention. Nebbett in his book  (pp. 439 - sometimes you can view sample chapters from Google books) lists the implementation code of KiDispatchException (in Example C.1). You have to read the code in  and there are several interesting points. First, let's concentrate on the case if the previous mode of the program is kernel mode (i.e., it's the kernel code which invokes the interrupt):
"After an exception has occurred, and in the absence of a debugger, execution will resume by default at the exception address. The assumption is that the cause of the exception will have been corrected, and the faulting instruction will now succeed. In the presence of a debugger, and if the debugger consumed the exception, execution will resume at the current EIP register value."
What's more important is the following description from : This should happen even before KiDispatchException is called.
However, when interrupt 0x2D is executed, Windows uses the current EIP register value as the exception address and increases the EIP register value by one.
Finally, it issues an EXCEPTION_BREAKPOINT (0x80000003) exception. Thus, if the ‘CD 2D’ opcode (‘INT 0x2D’ instruction) is used, the exception address points to the instruction immediately following the interrupt 0x2D instruction, as for other interrupts, and the EIP register value points to a memory location that is one byte after that.
According to , due to the above behaviors of Win32 exception handling, it could cause byte scission. When a user debugger (e.g., OllyDbg) decides to resume the execution using the EIP register value, its behavior will be different from a normal execution.
Leave a Reply.