Thứ Ba, 29 tháng 10, 2013

HACKING A COUNTERFEIT MONEY DETECTOR FOR FUN AND NON-PROFIT

By Ruben Santamarta @reversemode


In Spain we have a saying "Hecha la ley, hecha la trampa" which basically means there will always be a way to circumvent a restriction. In fact, that is pretty much what hacking is all about.
It seems the idea of 'counterfeiting' appeared at the same time as legitimate money. The Wikipedia page for Counterfeit money  is a fascinating read that helps explain its effects.
http://en.wikipedia.org/wiki/Counterfeit_money
Nowadays every physical currency implements security measures to prevent counterfeiting. Some counterfeits can be detected with a naked eye, while others need specific devices or procedures to be identified. In order to help employees, counterfeit money detectors can be found in places that accept cash, including shops, malls, postal offices, banks, and gas stations.
Recently I took a look at one of these devices, Secureuro. I chose this device because it is widely used in Spain, and its firmware is freely available to download. 
http://www.securytec.es/Informacion/clientes-de-secureuro
As usual, the first thing I did when approaching a static analysis of a device of this kind was to collect as much information as possible. We should look for anything that could help us to understand how the target works at all levels. 
In this case I used the following sources:
Youtube
http://www.youtube.com/user/EuroSecurytec 
I found some videos where the vendor details how to use the device. This let me analyze the behavior of the device, such as when an LED turns on, when a sound plays, and what messages are displayed. This knowledge is very helpful for understanding the underlying logic when analyzing the assembler later on.


Vendor Material
Technical specs, manuals, software, firmware ... [1] [2] [3] See references.
The following document provides some insights into the device’s security http://www.secureuro.com/secureuro/ingles/MANUALINGLES2006.pdf 
Unfortunately, some of these claims are not completely true and others are simply false. It is possible to understand how Secureuro works; we can access the firmware and EEPROM without even needing hardware hacking. Also, there is no encryption system protecting the firmware.
Before we start discussing the technical details, I would like to clarify that we are not disclosing any trick that could help criminals to bypass the device 'as is'. My intention is not to forge a banknote that could pass as legitimate, that is a criminal offense. My sole purpose is to explain how I identified the code behind the validation in order to create 'trojanized' firmware that accepts even a simple piece of paper as a valid currency. We are not exploiting a vulnerability in the device, just a design feature.


Analyzing the Firmware
This is the software that downloads the firmware into the device. The firmware file I downloaded from the vendor's website contains 128K of data that will be flashed to the ATMEGA128 microcontroller. So I can directly load it into IDA, although I do not have access to the EEPROM yet.

Entry Points
A basic approach to dealing with this kind of firmware is to identify some elements or entry points that can leveraged to look for interesting pieces of code. 
A minimal set includes:

Interruption Vector 
  1. 1. RESET == Main Entry Point
  2. 2. TIMERs
  3. 3. UARTs
  4. 4. SPI
Mnemonics
  1. 1. LPM (Load Program Memory)
  2. 2. SPM (Store Program Memory) 
  3. 3. IN
  4. 4. OUT
Registers

ADCL: The ADC Data Register Low
ADCH: The ADC Data Register High
ADCSRA: ADC Control and Status Register
ADMUX: ADC Multiplexer Selection Register 
ACSR: Analog Comparator Control and Status
UBRR0L: USART Baud Rate Register 
UCSR0B: USART Control and Status Register
UCSR0A: USART Control and Status Register
UDR0: USART I/O Data Register 
SPCR: SPI Control Register  
SPSR: SPI Status Register  
SPDR: SPI Data Register  
EECR: EEPROM Control Register  
EEDR: EEPROM Data Register  
EEARL: EEPROM Address Register Low 
EEARH: EEPROM Address Register High 
OCR2: Output Compare Register  
TCNT2: Timer/Counter Register   
TCCR2: Timer/Counter Control Register  
OCR1BL: Output Compare Register B Low
OCR1BH: Output Compare Register B High
OCR1AL: Output Compare Register A Low
OCR1AH: Output Compare Register A High
TCNT1L: Counter Register Low Byte 
TCNT1H: Counter Register High Byte 
TCCR1B: Timer/Counter1 Control Register B 
TCCR1A: Timer/Counter1 Control Register A 
OCR0: Timer/Counter0 Output Compare Register 
TCNT0: Timer/Counter0    
TCCR0: Timer/Counter Control Register  
TIFR: Timer/Counter Interrupt Flag Register 
TIMSK: Timer/Counter Interrupt Mask Register 
Using this information, we should reconstruct some firmware functions to make it more reverse engineering friendly.
First, I try to identify the Main, following the flow at the RESET ISR. This step is pretty straightforward.
As an example of collecting information based on the mnemonics, we identify a function reading from flash memory, which is renamed to 'readFromFlash'. Its cross-references will provide valuable information.
By finding the references to the registers involved in EEPROM operations I come across the following functions 'sub_CFC' and 'sub_CF3':

The first routine reads from an arbitrary address in the EEPROM. The second routine writes to the EEPROM. I rename 'sub_CFC' to 'EEPROM_read' and 'sub_CF3' to 'EEPROM_write'. These two functions are very useful, and provide us with important clues.
Now that our firmware looks like a little bit more friendly, we focus on the implemented functionalities. The documentation I collected states that this device has been designed to allow communications with a computer; therefore we should start by taking a look at the UART ISRs.
Tip: You can look for USART configuration registers UCSR0B, UBRR0... to see how it is configured. 
USART0_RX
It is definitely interesting, when receiving a 'J' (0x49) character it initializes the usual procedure to send data through the serial interface. It checks UDRE until it is ready and then sends outs bytes through UDR0. Going down a little bit I find the following piece of code
It is using the function to read from the EEPROM I identified earlier. It seems that if we want to understand what is going on we will have to analyze the other functions involved in this basic block, 'sub_3CBB' and 'sub_3C9F'.

SUB_3CBB
This function is receiving two parameters, a length (r21:r20) and a memory address (r17:r16), and transmitting the n bytes located at the memory address through UDR0. It basically sends n bytes through the serial interface.
I rename 'sub_3CBB' to 'dumpMemToSerial'. So  this function being called in the following way: dumpMemToSerial(0xc20,9). What's at address 0xc20? Apparently nothing that makes sense to dump out. I must be missing something here. What can we do? Let's analyze the stub code the linker puts at the RESET ISR, just before the 'Main' entry point. That code usually contains routines for custom memory initialization.
Good enough, 'sub_4D02' is a memory copy function from flash to SRAM. It uses LPM so it demonstrates how important it is to check specific mnemonics to discover juicy functions.
Now take a look at the parameters, at ROM:4041 it is copying 0x2BD bytes (r21:r20) from 0x80A1 (r31:r30) to 0xBC2 (r17:r16). If we go to 0x80A1 in the firmware file, we will find a string table!
Knowing that 0xBC2 has the string table above, my previous call makes much more sense now: dumpMemToSerial(0xc20,9) => 0xC20 - 0xBC2 = 0x5E
String Table (0x80A1) + 0x5E == "#RESETS" 
The remaining function to analyze is 'sub_3C9F', which is basically formatting a byte to its ASCII representation to send it out through the serial interface. I rename it 'hex2ascii'
So, according to the code, if we send 'J' to the device, we should be receiving some statistics. This matches what I read in the documentation. 
http://www.secureuro.com/secureuro/ingles/MANUALINGLES2006.pdf
Now this basic block seems much clearer. It is 'printing' some internal statistics.
"#RESETS: 000000" where 000000 is a three byte counter 
(“BILLETES” means “BANKNOTES” in Spanish)
"#BILLETES: 000000 "
("NO VALIDOS" means "INVALIDS" in Spanish)
#NO VALIDOS: 000000
...
Wait, hold on a second, the number of invalid banknotes is being stored in a three byte counter in the EEPROM, starting at position 0xE. Are you thinking what I’m thinking? We should look for the opposite operation. Where is that counter being incremented? That path would hopefully lead us to the part of code where a banknote is considered valid or invalid :) Keep calm and 'EEPROM_write'
Bingo!
Function 'sub_1FEB' (I rename it 'incrementInvalid') is incrementing the INVALID counter. Now I look for where it is being called.
'incrementInvalid' is part of a branch, guess what’s in the other part?
In the left side of the branch, a variable I renamed 'note_Value', is being compared against 5 (5€) 0xA (10€). On the other hand, the right side of the branch leads to 'incrementInvalid'. Mission accomplished! We found the piece of code where the final validation is performed.
Without entering into details, but digging a little bit further by checking where 'note_Value' is being referenced, I easily narrow down the scope of the validation to two complex functions. The first one assigns a value of either 1 or 2 to 'note_Value' :
The second function takes into account this value to assigns the final value. When 'note_Value' is equal to 1, the possible values for the banknotes are: 5,10, and 20. Otherwise the values should be 50, 100, 200, or 500. Why? 
I need to learn about Euro banknotes, so I take a look at the "Trainer's guide to the Eurobanknotes and coins" from the European Central Bank http://www.ecb.europa.eu/euro/pdf/material/Trainer_A4_EN_SPECIMEN.pdf
Curious, this classification makes what I see in the code actually make sense. Maybe, only maybe, the first function is detecting the hologram type, and the second function is processing the remaining security features and finally assigning the value. The documentation from the vendor states:
Well, what about those six analogue signals? By checking for the registers involved in ADC operations we are able to identify an interesting function that I rename 'getAnalogToDigital'
This function receives the input pin from the ADC conversion as a parameter. As expected, it is invoked to complete the conversion of six different pins; inside a timer. The remaining three digital signals with information about the distances can also be obtained easily. 
There are a lot of routines we could continue reconstructing: password, menu, configurations, timers, hidden/debug functionalities, but that is outside of the scope of this post. I merely wanted to identify a very specific functionality.
The last step was to buy the physical device. I modified the original firmware to accept our home-made IOActive currency, and...what do you think happened? Did it work? Press play to find it out ;)

video
The impact is obvious. An attacker with temporary physical access to the device could install customized firmware and cause the device to accept counterfeit money. Taking into account the types of places where these devices are usually deployed (shops, mall, offices, etc.)  this scenario is more than feasible.
Once again we see that when it comes to static analysis, collecting information about the target is as important as reverse engineering its code. Without the knowledge gained by reading all of those documents and watching the videos, reverse engineering would have been way more difficult. 
I hope you find this useful in some way. I would be pleased if this post encourages you to research further or helps vendors understand the importance of building security measures into these types of devices.
References:

[1]http://www.inves.es/secureuro?p_p_id=56_INSTANCE_6CsS&p_p_lifecycle=0&p_p_state=normal&p_p_mode=view&p_p_col_id=detalleserie&p_p_col_count=1&_56_INSTANCE_6CsS_groupId=18412&_56_INSTANCE_6CsS_articleId=254592&_56_INSTANCE_6CsS_tabSelected=3&templateId=TPL_Detalle_Producto
[2] http://www.secureuro.com/secureuro/ingles/menuingles.htm#
[3] http://www.secureuro.com/secureuro/ingles/MANUALINGLES2006.pdf

[4] http://www.youtube.com/user/EuroSecurytec

Thứ Hai, 28 tháng 10, 2013

Malware Analysis Tutorial 5: Int2d Anti-Debugging Trick (Part III)

Learning Goals:

  1. Apply the techniques presented in Tutorials 3 and 4 to analyzing Max++ anti-debugging trick.
  2. Practice reverse engineering/interpretation of Intel x86 assembly.
Applicable to:
  1. Computer Architecture
  2. Operating Systems Security
  3. Software Engineering

Challenge of the Day:
  1. Write a Python snippet for Immunity Debugger that executes Max++ and generates a log message for each INT 2D instruction executed.
1. Introduction

[Lab Configuration: we assume that you are running the VM instance using NON-DEBUG mode. We will use the Immunity Debugger in this tutorial.]
 
We now revisit Max++ and apply the knowledge we have obtained in Tutorial 3 and Tutorial 4. Figure 1 presents the disassembly of the first 20 instructions of Max++. The entry point is 0x00403BC8. Execute the code step by step until you reach 0x403BD5, now you are facing your first challenge: How do you deal with the INT 2D instruction?

There are several choices you could take: (1) Simply press F8 and IMM will SKIP the RETN instruction and directly jumps to 0x413BD8 (by executing the CALL 0x413BD8 instruction right after the RETN instruction); (2) Execute the RETN instruction by readjusting the EIP register to enforce its execution. In IMM, you can readjust the value of EIP by launching the Python window (clicking the 2nd button on the toolbar, on the right of the "open_file" button), and then executing the following Python command: "imm.setReg("EIP", 0x00413BD7);".

Figure 1. Entry Point of Max++

Which action to take will depend on the behavior of IMM -- if we press F8, will its behavior be the same as running the program without any debuggers attached? Following a similar approach taken in Tutorial 4 we can do an experiment for the case of EAX=1 (i.e., calling the debug print service of INT 2D). The conclusion is:

When the DEBUG-MODE is NOT enabled at booting, the behavior of IMM is the same as regular execution, given EAX=1 (note that in tutorial 4, our experiments explore the case when EAX=0). Hence, we can feel safe about stepping over (and skipping the RETN instruction) in IMM!

2.Diverting Control Flow using Int 2D

As shown in Figure 2, now we are at 0x00413A38. In this function, we only have four instructions: STD, MOV EDI, EDI, CALL 0x00413BB4, and IRETD.

The purpose of the STD instruction is to set the growth direction of EDI (i.e., direction flag)  to -1. EDI/ESI registers are frequently used in RAM copy instructions such as "REP STOSB" (to repeatedly copy from memory address pointed by ESI to the destination address pointed by EDI). Later we'll see the use of these instructions in the decoding of encrypted malicious code in Max++.

The MOV EDI,EDI instruction does nothing (no impacts on any flag registers) and then we are calling the function at 0x00413BB4.


Note that it looks like once we are back from 0x00413BB4, the next immediate instruction is to return (IRETD), however, it is not the case. Function 0x413BB4 will retrieve a section of encrypted code, decrypt them, and deploy it from the location of IRETD. So if a static analysis tool is used  to analyze the program, e.g., draw the control flow graph of Max++, it will mislead the malware analyzers. We'll get to the decoding function in the next tutorial.

Figure 2. Function 0x413A38

 Press "F7" to step into Function 0x00413BB4. Now we are getting to the interesting point. Look at instruction CALL 0x00413BB9 at 0x413BB4 in Figure 3!

  The CALL instruction basically does two things: (1) it pushes the address of the next instruction to the stack (so when the callee returns, the execution will resume at the next instruction); If you observe the stack content (the pane on the right-bottom on IMM), you will notice that 0x413BB9 is pushed into stack. (2) It then jumps to the entry address of the function, which is 0x00413BB9.

 Now the next two instructions is to call the INT 2D service. Notice that the input parameter EAX is 3 (standing for the load image service). Using an approach similar to Tutorial 4, you can design an experiment to tell what is the next action you would take. The conclusion is: when EAX is 3, in the non-kernel-debug mode, the IMM behavior is the same as normal execution, which is: the next immediate byte instruction after INT 2D will be skipped.

  Now, what if the RETN instruction is executed (i.e., the byte instruction is not skipped, assume that an automatic analyzer does not do a good job at handling INT 2D)? You will jump directly and return. The trick is as follows: Recall that RETN takes out the top element in stack and jump to that address. The top element in stack is now 0x00413BB9. So what happens is that the execution comes back to 0x00413BB9 again. Then doing the INT 2D again and RETN again will force the execution to 0x00413A40 (the IRETD instruction, which is right after the CALL 0X00413BB4 in function 0x00413A38 (see Figure 2)). It then returns to the main program and exits. So the other malicious activities will not be performed in this scenario. To this point, you can see the purpose of the int 2d trick: the malware author is trying to evade automatic analysis tools (if they did not handle int 2dh well) and certain kernel debuggers such as WinDbg.

Challenge of the day: use WinDbg instead of Immunity Debugger to debug through Max++ (with DEBUG-MODE enabled at booting). What is your observation?


Figure 3. Trick: Infinite Loop of Call


3. Conclusion
  We have shown you several examples of the use of INT 2D in Max++ to detect the existence of debugger and change malware behavior to avoid being analyzed by a debugger. For debugger to cope with INT 2D automatically will not be an easy job. First, there are many scenarios to deal with (affected by the type of debugger, existence of kernel debugger, and the booting options). Second, don't expect to catch all INT 2D instructions when the program is loaded, because a program can be self-extracting (modifying its code segment at run time).

4. Challenge of the Day
  It is beneficial to write a Python script that drives the Immunity Debugger to cope with INT 2D automatically. We provide some basic ideas here:

In IMM, there is a global variable "imm" for you to drive the debugger. You can use "imm" to inspect all register values, set all register values (thus including modifying EIP to change control flow), examine and modify RAM. Your program will be a simple loop, which executes instructions one by one (to do this, you can take advantage of breakpoint functions available in the Python API of IMM). Before executing an instruction, you can examine its opcode (using libanalyze.opcode, check the IMM documentation), and take proper actions for INT 2D (skipping the next byte based on the value of EAX, to simulate a normal non-debug environment).

Malware Analysis Tutorial 4: Int2dh Anti-Debugging (Part II)

Learning Goals:
  1. Explore the behavior difference of debuggers on int 2dh.
  2. Debugging and modification of binary executable programs.
  3. Basic control flow constructs in x86 assembly.
Applicable to:
  1. Computer Architecture
  2. Operating Systems
  3. Operating Systems Security
  4. Software Engineering

Challenge of the Day:
  1. Find out as many ways as possible to make a program run differently in a debugged environment from a regular execution (using int 2d)?
1. Introduction

The behavior of int 2d instructions may be affected by many factors, e.g., the SEH handler installed by the program itself, whether the program is running under a ring 3 debugger, whether the OS is running in the debugged mode, the program logic of the OS exception handler (KiDispatch), the value of registers when int 2d is requested (determining the service that is requested). In the following, we use an experimental approach to explore the possible ways to make a program behave differently when running in a virtual machine and debugged environment.

2. Lab Configuration

In addition the the immunity debugger, we are going to use WinDbg in this tutorial. Before we proceed, we need to configure it properly on the host machine and the guest XP.

If you have not installed the guest VM, please follow the instructions of Tutorial 1. Pay special attention to Seciton 3.1 (how to set up the serial port of the XP Guest). In the following we assume that the pipe path on the host machine is \\.\pipe\com_11 and the guest OS is using COM1. The installation of WinDbg on the host machine can follow the instructions on MSDN.

We need to further configure the XP guest to make it work.

(1) Revision of c:\boot.ini. This is to set up a second booting option for the debug mode. The file is shown as below, you can modify yours correspondingly. Note that we set COM1 as the debug port.

-------------------------------------
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="DEBUGGED VERSION" /noexecute=optin /fastdetect /debug /debugport=com1 /baudrate=115200

------------------------------------

(2) Manual configuration of COM ports. In some versions of XP, COM ports have to be manually configured. You can follow jorgensen's tutorial on "How to Add a Serial Port in Windows XP and 7 Guest" (follow the XP part). It consists of two steps: (1) manually add a COM port in Control Panel and (2) manually configure COM1 as the port number.

(3) Test run of WinDbg.
Start your XP guest in the debug mode (2nd option).

Now in the host machine, launch the "Windows SDK 7.1" command window coming with WinDbg. Change directory to "c:\Program Files\Debugging Tools for Windows(x86)" and type the following. You should be able to get a window as shown in Figure 1.

windbg -b -k com:pipe,port=\\.\pipe\com_11

You might notice that currently you are not able to access your XP Guest. This is because WinDbg stops its running, Simply type "g" (standing for "go") in the WinDbg window, and let the XP Guest continue.
Figure 1: Screenshot of WinDbg


3. Experiment 1: Int 2d on Cygwin

In the following, we demonstrate some of the interesting behaviors of Int 2d using a simple program Int2dPrint.exe. The C++ source of the program is shown in the following. The output of the program should be "AAAABBBB". We added a fflush(stdout) to enforce the output in an eager mode and before each printf() statement, there are five integer operations to allow us insert additional machine code later.

----------------------------------------------
#include <stdio.h>

int main(){
  int a = 0;
  int b = 0;
  int c = 0;
  int d = 0;
  int e = 0;
  printf("AAAA");
  fflush(stdout);

  a = 0; b = 0; c = 0; d = 0; e = 0;
  printf("BBBB");
  fflush(stdout);
}
--------------------------------------------
                     Source code of Int2dPrint.exe

Figure 2 shows the assembly of the compiled code.Clearly,the 'MOV [EBP-xx], 0' instructions between 0x4010BA and 0x4010D6 correspond to the integer assignments "int a=0" etc. in the source program. The "MOV [ESP], 0X402020" at 0x4010DD is to push the parameter (the starting address of constant string "AAAA") into the stack, for the printf() call. Also note that before the fflush call at 0x4010F4, the program calls cygwin.__getreent. It is to get the thread specific re-entrant structure so that the stdout (file descriptor of the standard output) can be retrieved. In fact, you can infer that the stdout is located at offset 0x8 of the reentrant structure.

Figure 2. Compiled Binary of Int2dPrint.cc
3.1 Patching Binary Code

Now let us roll our sleeves and prepare the patch the Int2dPrint.exe. The binary program is compiled using g++ under Cygwin. To run it, you need the cygwin1.dll in Cygwin's bin folder. You can choose to compile it by yourself, or use the one provided in the zipped project folder.

Make sure that your XP guest is running in NON-DEBUG mode!

We now add the following assembly code at location 0x4010F9 of Int2dPrint.exe (the first "int a=0" before the printf("BBBB")). Intuitively, the code tests the value of EAX after the int 2d call. If EAX is 0 (here "JZ" means Jump if Zero), the program will jump to 0x401138, which skips the printf("BBBB"). Notice that this occurs only when the instruction "inc EAX" is skipped.

------------------------------------
 
xor EAX, EAX       # set EAX=0;
int 2d                      # invoke the exception handler
inc EAX                 # if executed, will set EAX=1
cmp EAX, 0
JZ 0x401138         # if EAX=0, will skip printf("BBBB");
-----------------------------------
     The assemble Code to Insert

The following shows you how to patch the code using IMM:
(1) Right click at 0x4010F9 in the CPU pane, and choose "Assemble". (Or simple press Spacebar at the location). Enter the code as above.
(2) Right click in the CPU pane, choose "Copy to Executable" --> "All Modified", then click "Copy All". A window of modified instructions will show up. Close that window and click "Yes" to save. Save the file as Int2dPrint_EAX_0_JZ0.exe. The name suggests that the EAX input parameter to the int 2d service is 0, and we expect it to skip the printf("BBBB") if EAX=0, i.e., the output of the program should be "AAAA". (this, of course, depends on whether the "inc EAX" instruction is executed or not).

In Figure 3, you can find the disassembly of Int2dPrint_EAX_0_JZ0.exe. Setting a breakpoint at 0x004010BA, you can execute the program step by step in IMM. You might find that the output is "AAAA" (i.e., "BBBB" is skipped). It seems to confirm the conclusion of byte scission of int 2d.You can also run the program in a command window, the output is the same.

Figure 3. Disassembly of Int2dPrint_EAX_0_JZ0.exe

But wait, how about another experiment. Let's modify the instruction at 0x401101 and make it "JNZ 0x401138" (name it as Int2dPrint_EAX_0_JNZ0.exe). What is the expected output? "AAAABBBB"? You might find that in IMM, the program outputs "AAAABBBB"; but if run in command window, it generates "AAAA" only!!! (Notice that we have ruled out the possibility that the I/O output was lost in buffer - because we call the fflush(stdout) to enforce all outout immediately). What does this mean? There could be two possibilities:

  (1). Somehow, the instruction "INC EAX" is mysteriously executed (in the regular execution of Int2dPrint_EAX_0_JNZ0.exe). This makes no sense, because prior to 0x401101, the program is exactly the same as Int2dPrint_EAX_0_JZ0.exe.

 (2). There is something tricky in the exception handler code (it could be the SEH of the program itself, or the KiDispatch in the kernel).

 We will later come back to this strange behavior, and provide an explanation.

 3.2 Experiments with Kernel-Debugging Mode

  Now let's reboot the guest OS into the DEBUG mode (but without launching WinDbg in the host machine). Let's re-run the two programs, you might have some interesting finding. Both programs hang the guest OS!

  Now let's reboot the guest OS again into the DEBUG mode and launch WinDbg in the host machine (press "g" twice to let it continue). Now start the Int2dPrint_EAX_0_JNZ0.exe in command window. What is your observation? Figure 4 displays the result: the debugger stops at 0x4010fd (the "inc EAX" instruction) on exception 80000003 (the exception code "BREAKPOINT" in windows)! If you type "g", the program will proceed and produce "AAAA"! (while in the non-debugged windows mode and command window, it's producing "AAAABBBB"!)

Figure 4: Running Result of Int2dPrint_EAX_0_JNZ0.exe

 3.2 Discussion

 Now let us summarize our observations so far in Table 1 (I did not discuss some of the experiments here but you can repeat them using the files provided).

Table 1: Summary of Experiment 1

    To simply put: int 2dh is a much more powerful technique to examine the existence of  debuggers than people previously thought (see the reference list of tutorial 3). It can be used to detect the existence of both ring 3 (user level) and ring 0 (kernel level) debuggers. For example, using Table 1, we can easily tell if Windows is running in DEBUG mode (i.e., kernel debugger enabled) or not, and if a kernel debugger like WinDbg is hooked to the debug COM port or not. We can also tell the existence of a user level debugger such as IMM, whether windows is running in non-debug or debug mode. The delicacy is that the final output of the int 2dh instruction is affected by many factors, and experiment 1 only covers a subset of them. The following is a re-cap of some of the important facts:
  1. EAX, ECX, EDX are the parameters to the int 2d service. EAX (1,2,3,4) represent the printing, interactive prompt, load image, unload image. See Almeida's tutorial for more details.Notice that we are supplying an EAX value 0, which is not expected by the service! (normal values should be from 1 to 4).
  2. Once the int 2d instruction is executed, CPU locates the interrupt vector and jumps to the handler routine, which is the part of OS.
  3. OS wraps the details of hardware exception, and generates kernel data structures such as Exception_Record, which contains Exception Code: 80000003 (represents a breakpoint exception).
  4. Then control is forwarded to kernel call KiDispatchException, which depending on if Windows is running in kernel mode, exhibits very sophisticated behavior. See details in G. Nebbett, "Windows NT/2000 Native API Reference" (pp 441 gives pseudo code of KiDispatchException). For example, in windows debug mode, this generally involves forwarding the exception to debugger first (calling DbgkForwardException), and then the invocation of user program installed SEH handlers, and then forward the exception to debugger a second time.  


We now proceed to briefly explain all the behaviors that we have observed.

  Case 1. Non-Debug Mode and Command Window (column 2 in Table 1): this is the only case that Int2dPrint_EAX_0_JZ0.exe and Int2dPrint_EAX_0_JNZ0.exe behave the same way. There is only one explanation: the inc EAX is not executed - not because the exception handling behaves differently in a debugged environment, but because the entire process is terminated. To illustrate the point, observe the two screenshots in Figure 5, which are generated by the IMM debugger via (View->SEH Chain). Diagram (a) shows the SEH chain when the program is just started, you can see that the default handler kernel32.7C839AC0 (means the entry address of the handler is 7c839ac0 and it is located in kernel32). If you set a breakpoint right before the printf(), you might notice that the SEH chain now includes another handler from cygwin (in Fig 5(b))! It's the cygwin handler which directly terminates the process (without throwing any error messages); if it is the kernel32 handler, it would pop a standard windows error dialog.

Figure 5: SEH Chain of Int2dPrint_EAX_0_JZ0.exe before and after reaching the main()


  Case 2. Non-Debug Mode and IMM Debugger (column 3 in Table 1): Based on the logic of the two programs, you can soon reach the conclusion that the byte instruction right after int 2dh is skipped! There are two observations here: (1) the Cygwin handler is NEVER executed! This is because the Immunity Debugger takes the control first (Recall the logic of KiDispatchException and the KiForwardException to debugger port). (2) Immunity Debugger modifies the value of EIP register, because the exception is a breakpoint. See discussion in Ferrie's article about IMM's behavior [1]. The result of shifting one byte, however, is also affected by the kernel behavior (look at the EIP-- operation in KiDispatchException (see pp. 439 of Nebbett's book [2]). The combined effect is to shift one byte. Note that if replacing IMM with another user level debugger such as IDA, you might have a different result.

 Case 3. Debug Mode without WinDbg Attached and CMD shell (column 4 in Table 1): windows freeze! The reason is clear: no debuggers are listening to the debug port and the breakpoint exception is not handled (no one advances the EIP register).

Case 4. Debug Mode without WinDbg Attached and Run in IMM (column 5 in Table 1): This is similar to case 2. If you F9 (and run the program) in IMM, you might notice that IMM stops at the SECOND instruction  right after int 2dh (i.e, "CMP EAX,0") first (because it's a breakpoint exception, but the kernel debugging service is actually not triggered). If you F9 (continue) the program, it continues and exhibits the same behavior as Case 2. Again, the byte scission is the combined result of IMM and the kernel behavior (on int exceptions).

Case 5. Debug Mode with WinDbg Attached and Run in CMD shell (column 6 in Table 1):In this case, WinDbg stops at the instruction right after int 2dh (i.e., "inc EAX") and if continues, executes the "inc EAX" instruction.

Case 6. Debug Mode with WinDbg Attached and Run in IMM (column 7 in Table 1):In this case, WinDbg never gets the breakpoint exception, it's the user level debugger IMM gets the breakpoint exception first and like case 4, IMM readjusts the EIP register so that it stops at the SECOND INSTRUCTION after int 2d. It is interesting to note that, even when WinDbg is initiated, if you start a user debugger, it gets/overrides the WinDbg on the processing of breakpoints. This is of course understandable -- think about using Visual Studio in the debugged mode for debugging a program, it is natural to pass the breakpoint event to Visual Studio first. Once the user level debugger declares that the exception has been handled, there is no need to to pass to the kernel debugger for handling.

Clearly, IMM debugger has a "defect" in its implementation. First, it blindly processes a breakpoint exception even if this is not a registered exception in its breakpoint list. Second, the kernel service handles the readjustment of EIP differently for int 3 and int 2d (even though both of them are wrapped as the 80000003 exception in windows). When IMM does not differentiate the cases, the combined effect is that the readjustment of EIP is "over-cooked" and we see the byte scission.

3.3 Challenges of the Day

All of the above discussion are based on the assumption that EAX is 0 when calling the int 2d service. Notice that this is a value unexpected by the windows kernel -- the legal values are 1, 2, 3, and 4 (debug print, interactive, load image, unload image). Your challenges today is to find out the cases when EAX is set to 1, 2, 3, 4, and other unexpected values and assess the system behavior. You will have interesting discoveries.




4. Experiment 2: notepad


There is another interesting area we have not explored: the user installed SEH. The Int2d programs are good examples. The preamble code before the main function installs an SEH handler offered by Cygwin. It immediately leads to the termination of the process. It is interesting to observe the behavior of the default kernel32 handler. The following experiment sheds some light.


4.1 Experiment Design
When we use File->Open menu of notepad, we will always see a dialog popped up. Our plan is to insert the code in Section 3.1 before the call for popping dialog, and observe if there is any byte scission.


The first question is how to locate the code in notepad.exe that launches a file open dialog. We will again use some immunity debugger tricks. It is widely known that user32.dll provides important system functions that are related to graphical user interface. We could examine the visible functions by user32.dll using the following approach.
  1. Open notepad.exe (in c:\windows) using the Immunity Debugger
  2. View -> Executable Modules
  3. Right click on "user32.dll" and select "View->Names". This exposes the entry address of all externally visible functions of the dll. Browse the list of functions, we may find a collections of functions such as CreateDialogIndirectParamA and CreateDialogIndirectParamW. Press "F2" to set a software breakpoint on each of them. 
  4. Now F9 to run the notepad program. Click File->Open and the IMM stops at 7E4EF01F. Go back to the View->Names window, you will find that it is the entry address of CreateDialogIndirectParamW.
  5. Now remove all other breakpoints (except CreateDialogIndirectParam), so that we are not distracted by others. You can do this in View->Breakpoints window to remove the ones you don't want.
  6. Restart the program (make sure that your BP is set), click file->open, now you are stopping at CreateDialogIndirectParamW. We will now take advantage of once nice feature in IMM. Click Debug-> Execute Till User Code (to allow us get to the notepad.exe code directly!). Note that since the dialog is a modal dialog (which sticks there until you respond), you have to go back to the running notepad and cancel the dialog. Then the IMM stops at instruction 0x01002D89 of notepad.exe! This is right after the call of GetOpenFileNameW, which we just returns from.

Figure 6. Disassembly of notepad.exe


 The disassembly of notepad.exe is quite straightforward. At 0x01002D27, it sets up the dialog file filter "*.txt", and then at 0x01002D3D, it calls the GetOpenFileW function. The return value is stored in EAX. At 0x01002D89, it tests the value of EAX. If it is 0 (meaning the file dialog is canceled), the program control jumps to 0x01002DE0 (which directly exists the File->open processing).

  We now can insert our instructions (most from Section 3.1) at 0x01002D27 (the side-effect is that the dialog file filter is broken - but this is ok). The code is shown below (we call it notepad_EAX_0_JZ0.exe. Similarly, we can generate notepad_EAX_0_JNZ0.exe):

------------------------------------
 
xor EAX, EAX       # set EAX=0;
int 2d                      # invoke the exception handler
inc EAX                 # if executed, will set EAX=1
cmp EAX, 0
JZ 0x01002D89         # if EAX=0, will skip printf("BBBB");
-----------------------------------
 
Run notepad_EAX_0_JZ0.exe in a command window (undebugged window), you will get the standard exception window thrown by windows. If you click the "details" link of the error dialog, you will be able to see the detailed information: note the error code 0x80000003 and the address of the exception (0x01002D2B!). I believe now you can easily draw the conclusion about the exception handler of kernel32.dll.



Figure 7: Error Report


4.2 Challenge of the Day

Our question is: are you sure that the error dialog is thrown by the handler of kernel32.7C839AC0? Prove your argument.


5. Experiment 3: SEH Handler Technique

Recall that the SEH handler installed by the user program itself can also affect the running behavior of int 2d. For example, Int2dPrint_EAX_0_JZ0.exe installed a handler in Cygwin1.dll, it leads to the termination of the process immediately; while the default kernel32.dll handler throws out an exception dialog that displays debugging information. In this experiment, we repeat Ferrie's example in [3] and explore further potential possibilities of anti-debugging.

Figures 8 and 9 present our slightly adapted version of Ferrie's example in [3] . The program is modified from the Int2dPrint.exe. The first part of the code is displayed in Figure 8, starting from 0x004010F9 and ending at 0x0040110E. We now briefly explain the logic.

Basically, the code is to install a new exception handler registration record (recall that SEH is a linked list and each registration record has two elements: prev pointer and the entry address of handler). So instruction at 0x004010FB is to set up the handler address attribute to 0x004016E8 (we'll explain later), and at 0x00401100 it is to set the prev pointer attribute. Then the instruction at 0x00401103 resets FS:[0], which always points to the first element in the SEH chain. The rest of the code does the old trick: it puts an "INC EAX" instruction right after the int 2d instruction and depending on whether the instruction is skipped, it is able to tell the existence of debugger.

Figure 8. Part I of Ferrie's Code


We now examine the exception handler code at 0x004016E8. It is shown in Figure 9, starting at 0x004016E8 and ending at 0x004016F4. It has three instructions. At 0x004016E8, it puts a word 0x43434343 into address 0x00402025. If you study the instruction at 0x0040111c (in Figure 8), you might notice that at 0x00402025, it stores the string "BBBB". So this instruction is essentially to store "CCCC" into the RAM. If the SEH handler is executed and if the second printf() statement is executed, you should see "AAAACCCC" in output, instead of "AAAABBBB". You might wonder, why not just change the value of a register (e.g., EBX) in the handler to indicate that the SEH is executed? Recall that interrupt handler of OS will recover the value of registers from kernel stack - no matter what value you set on a register (except for EAX), it will be wiped out by OS after return.

The last two instructions of the SEH handler simply returns 0. Notice that, as shown by Pietrek in [1], "0" means ExceptionContinueExecution, i.e., the exception has been handled and the interrupted process should resume. There are other values that you can play with, e.g., "1" means ExceptionContinueSearch, i.e., this handler could not solve the problem and the search has to be continued on the SEH chain to find the next handler. Note that these values are defined in the EXCEPT.h.


Figure 9. Part II of Ferrie's Code

 There could be another factor that affects your experimental results. The immunity debugger can be configured on whether or not to pass the exception to a user program. Click the "Debugger Options" menu in IMM, and then the "Exceptions" tab (shown in Figure 10). You can specify to pass all exceptions to user programs (by clicking the "add range" button and select all exceptions). After the configuration is done, running the program using "Shift + F9" will pass the exceptions to user installed SEH (compared with F9).

Figure 10. Configuration of Exception Handling of IMM

Similar to Section 4, we can run our program (Int2dprint_EAX0_RET0_JZ0.exe, meaning setting EAX to 0 when calling int 2d, and returning 0 in the SEH handler), under different environments, with debugging mode turned on or not. The results are displayed in Figure 11.

Non-debug mode: when running in command window, the output is "AAAACCCC". Clearly, the user installed SEH is executed and the byte scission did not occur (i.e., the "inc EAX" instruction is indeed executed). Compare it with the similar running environment in Table 1, you can immediately understand the effect of returning 0 in SEH: it tells the OS: "everything is fine. Don't kill the process!".

If you run the program in IMM, using F9 (without passing exceptions to user program), the result is "AAAA", where the "inc EAX" is skipped by IMM (similar to Table 1) and the user installed SEH is never executed; however, if you choose shift+F9 to pass exceptions to user program, the SEH is executed and the "inc EAX" is executed! It seems that in the "shift+F9" mode, IMM's does not re-adjust the EIP (as stated in Ferrie's article).

Debug-Mode with WinDbg Attached: Now when WinDbg is attached, the command line running of the program yields "AAAABBBB". This means that "inc EAX" is executed but the SEH is not executed! I believe, similarly, you can explain the IMM running result.

Now, the conclusion is: the use of user installed SEH enables more possibilities to detect the existence of debuggers and how they are configured!

Figure 11. Experimental Results of Ferrie's Example

5.1 Challenges of the Day

Play with the return values of your SEH handler, set it to 1, 2, and other values such as negative integers. What is your observation?


6. Conclusion

The int 2d anti-debugging technique is essentially an application of OS finger printing, i.e., from the behaviors of a system to tell its version and configuration. From the point of view of a program analysis researcher, it could be a very exciting problem to automatically generate such anti-debugging techniques, given the source/binary code of an operating system.


References

[1] M. Pietrek, "A Crash Course on the Depth of Win32Tm Structured Exception Handling," Microsoft System Journal, 1997/01. Available at http://www.microsoft.com/msj/0197/exception/exception.aspxhttp://www.microsoft.com/msj/0197/exception/exception.aspx.

[2] G. Nebbett, "Windows NT/2000 Native API Reference", pp. 439-441, ISBN: 1578701996.

[3] P. Ferrie, "Anti-Unpacker Tricks - Part Three", Virus Bulletin Feb 2009. Available at http://pferrie.tripod.com/papers/unpackers23.pdf, Retrieved 09/07/2011.

Malware Analysis 3: int2d anti-debugging (Part I)

Learning Goals:
  1. Understand the general interrupt handling  mechanism on X86 platform.
  2. Understand the byte scission anti-debugging technique.
  3. Know how to use a binary debugger to patch an executable program
Applicable to:
  1. Computer Architecture
  2. Operating Systems
  3. Principles of Programming Languages

Challenge of the Day:
  1. Analyze the code between 0xaaaa and 0xaaaa. What is its purpose?

1. Introduction

  To prolong the life of a malware, anti-debugging techniques are frequently used to delay the analysis process performed by security experts. This lesson presents "int 2d", an example of the various anti-debug techniques employed by Max++. Bonfa has provided a brief introduction of this technique in [1]. Our analysis complements [1], and presents an in-depth analysis of the vulnerabilities of debuggers.

  The purpose of anti-debugging is to hinder the process of reverse engineering. There could be several general approaches: (1) to detect the existence of a debugger, and behave differently when a debugger is attached to the current process; (2) to disrupt or crash a debugger. Approach (1) is the mostly frequently applied (see an excellent survey in [2]). Approach (2) is rare (it targets and attacks a debugger - and we will see several examples in Max++ later). Today, we concentrate on Approach (1).

  To tell the existence of a debugger, as pointed by Shields in [2], there are many different ways. For example, an anti-debugging program can call system library functions such as "isDebuggerPresent()", or to examine the data structure of Thread Information Block (TIB/TEB) of the operating system. These techniques can be easily evaded by a debugger, by purposely masking the return result or the kernel data structure of the operating system.

  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.


Figure 1. Snapshot of Max++ Entry Point
2. Background Information

  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)?

  We need to read some background information of "INT 2D". Please take one hour and read the following related articles carefully. (Simply search for the "int 2d", and ignore the other parts).

  1. Guiseppe Bonfa, "Step-by-Step Reverse Engineering Malware: ZeroAccess / Max++ / Smiscer Crimeware Rootkit", Available at http://resources.infosecinstitute.com/step-by-step-tutorial-on-reverse-engineering-malware-the-zeroaccessmaxsmiscer-crimeware-rootkit/
  2. Tyler Shields, "Anti-Debugging - A Developer's View", Available at http://www.shell-storm.org/papers/files/764.pdf
  3. P. Ferrie, "Anti-Unpacker Tricks - Part Three", Virus Bulletin Feb 2009. Available at http://pferrie.tripod.com/papers/unpackers23.pdf, Retrieved 09/07/2011.
Let's summarize the conclusion of the above related work:
  1. Bonfa in [1] points out that the "int 2d" instruction will trigger an interrupt (exception). When a debugger is attached, the exception is handled; and when a debugger is not attached, the program (Max++) will be able to see the exception. The execution of "int 2d" will cause a byte scission (the next immediate byte following "int 2d" will be skipped). However, no explanation is provided for this byte scission. A solution is given: use the StrongOD plug-in for OllyDbg to handle the correct execution of "int 2d". We could not repeat the success of StrongOD on IMM, however, the readers are encouraged to try it on OllyDbg.
  2. Shields in [2] gives a high-level language example of the int 2d anti-debugging trick. The example is adapted from its section III.A (the int 3 example). This example explains how the malware can "see" the debugger, using a try-catch structure. when a debug IS attached, the "try-catch" will not be able to capture that exception (because the debugger has already handled the exception).; When no debugger is attached, its "try-catch" struct can capture the "int 3 (or 2d)" exception (thus set a flag which indicates a debugger is not attached);
  3. Ferrie in [3] gives an explanation of the reason why there is a byte scission of program execution. Ferrie gives an excellent example in Section 1.3 of [3]. We added a number of comments for each instruction. This example corresponds to the high-level language example in [2], however, at the assembly level and relies on a OS support for exception handling, called "SEH" (Structured Exception Handling). We will later come back to this example and explain its details after introducing SEH in Section 3.
               ----------------------------------------------------------------------------------
      1      xor eax, eax           
      2      push offset l1         
      3      push d fs:[eax]
      4      mov fs:[eax], esp
      5      int 2dh                
      6      inc eax                
      7      je being_debugged      
      8          ...
      9  l1: xor al, al             
      10     ret                     
                 ----------------------------------------------------------------------------------
          Listing 1. The int 2dh example from  P. Ferrie, "Anti-Unpacker Tricks - Part Three", VB2009

3. Structured Exception Handling

3.1 Interrupt and Exceptions

  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 [5] (ch6: interrupt and exception overview). Some important facts are listed below:
  1. Interrupts happen due to hardware signals (e.g., I/O completion signals, and by executing INT xx instructions). They happen at random time (e.g., I/O signal), except the direct call of INT instructions.
  2. Exceptions occurs when CPU detects error when executing an instruction.
  3. When an interrupt/exception occurs, normal execution is interrupted and CPU jumps to the interrupt handler (a piece of code that handles the interrupt/exception). When interrupt handler completes, the normal execution resumes. Interrupt handlers are loaded by OS during system booting, and there is an interrupt vector table (also called interrupt descriptor table IDT) which defines which handler deals with which interrupt.
  4. In general there are following interrupts/exceptions: (1) software generated exceptions (INT 3 and other INT n instructions - note the discussion of "not pushing error code into stack" for INT n instructions), (2) machine checking interrupts (not interesting to us at this point), (3) fault - an exception that can be corrected, when the execution resumes, it executes the same instructions (which triggers the exception) again, (4) trap - different from fault in that when resuming, it resumes from the next immediate instruction (to be executed), (5) abort (severe errors, not interesting to us at this point). If you look at Table 6-1, the divide by 0 exception and protection error are fault, and the INT 3 (software breakpoint) is a trap. Section 6.6 gives you a clear idea of the difference between fault and trap.
  5. When an interrupt/exception happens, the CPU pushes the following information (varies depending on the type of interrupt/exception): EIP, CS and flag registers, and ERROR CODE into the stack. Then find out the entry address of the interrupt handler using IDT, and jumps to it. Note that the saved EIP/CS (return address) depends on if it is a fault and trap! Then the interrupt handler will take over the job, and when resuming, use the information of the saved EIP/CS.


3.2 Structured Exception Handling

   Different from Intel IA32 Manual, Microsoft WIN32 encapsulates the details of interrupt handling. An MSDN article [6] provides an overview. In Win32 portable interrupt handling service, all hardware signals (irrepeatable and asynchronous) are treated as "interrupts"; and all other replicable exceptions (including faults, traps, and INT xx instructions) are treated as exceptions in Win32, and all exceptions are handled using a mechanism called Structured Exception Handling (SEH) [this includes the case int 2dh!]. M. Peitrek provides an excellent article [4] on the Microsoft System Journal, which reveals the internals of SEH. We recommend you thoroughly read [4] before proceeding to our discussion next.
3.3 Structured Exception Handling.

  Figure 2 displays a general procedure to handle an exception. When a program generates an error (e.g., divide by 0 error), CPU will raise an exception. By looking at the IDT (interrupt dispatch table), CPU retrieves the entry address of the interrupt service handler (ISR).  In most cases, the Win32 ISR will call KiDispatchException (we will later come back to this function). Then the ISR will look for user defined exception handlers, until one handles the error successfully. There are several interesting points here:
  1. The ISR needs to find a user-defined handle (e.g., the catch clause in the program). Where to find it? The memory word at FS:[0] contains the entry address. Here FS, like CS, DS, and SS, is one of the segment registers in a X86 CPU. In Win32, FS register always points to a kernel data structure TIB (Thread Information Block). TIB records the important system information (such as stack top, last error, process ID) of the current thread being executed. The first memory word of TIB is the address of the Exception Handler Record which contains the information. Thus from FS:[0] (meaning the word at the offset 0 starting from segment base FS), ISR could invoke the user-defined handlers. For more information on TIB, you can read [8].
  2. Notice that there is a CHAIN OF HANDLERS! This is natural because you might have nested try-catch statement. In addition, in the case the error is not handled by the user program, the system will anyway provides a handler which terminates the user application and popping a Windows error dialog which shows you "Program error at 0xaabbcc, debug or terminate it?". Where to place this chain of handlers? It's the stack of the user program. Each element if the chain is an instance of the _EXCEPTION_REGISTRATION data structure. Read [4] for more details! To make a complete story, the _EXCEPTION_REGISTRATION struct from [4] is shown in the following: here "dd" stands for "double word" (32-bit memory word). The "prev" field points to the previous exception registration record and the "handler" is the entry address of the handler.

                  
_EXCEPTION_REGISTRATION struc
prev    dd      ?
handler dd      ?
_EXCEPTION_REGISTRATION ends


     3. How does ISR tell when to stop? When a user-defined handler returns 0 (ExceptionContinueExecution), the ISR can resume the user process. When a handler returns 1 (ExceptionContinueSearch), the IRS will have to search in the chain for the next handler. The definition of ExceptionContinueExecution can be found in the definition of EXCEPTIOn_DISPOSITION in  EXCPT.h (you can easily google to find its source file).
Figure 2. General Procedure of Handling an Exception

3.3 Revisit of Ferrie's Example [3]

  With the information of 3.2, we are now able to completely understand the details of Ferrie's example. Some important points are listed below:
  1. Instructions 2 to 4 builds a new _EXCEPTION_REGISTRATION record. Instruction 2 sets up the handler entry address, instruction 3 sets the "prev" link, and instruction 4 makes FS:[0] to point to the new record
  2. Instruction 9 sets the value of the AL register to 0. This is essentially to return 0 (ExceptionContinueExecution). This is to inform the IRS that the error is handled and there is no need to look for other handlers. Then the IRS will resume the normal execution (the old instruction might be re-executed, or it starts from the next immediate instruction. This will depend on the type of the fault/trap, see Intel IA32 manual chapter 6).

       ----------------------------------------------------------------------------------
      1      xor eax, eax           # EAX = 0        
      2      push offset l1         # push the entry of new handler into stack
      3      push d fs:[eax]        # push the old entry into stack
      4      mov fs:[eax], esp      # now make fs:[0] points to the new _Exception_Registration record
      5      int 2dh                # interrupt -> CPU will jump to l1
      6      inc eax                # EAX = 1, will be skipped (when debugger attached)
      7      je being_debugged      # if EAX=0, an debugger is there
      8          ...
      9  l1: xor al, al            # handler: set AL=0 (this is to return 0)
      10     ret                     
          ----------------------------------------------------------------------------------
          Listing 2. Ferrie's Example with Comments , "Anti-Unpacker Tricks - Part Three", VB2009


3.4 Int 2D Service

  We now examine some important facts related to INT 2d.  Almeida provides an excellent article about the INT 2d service and kernel debugging. We recommend a thorough reading of this article [7].

  INT 2d is the interface for Win32 kernel to provide kernel debugging services to user level debuggers and remote debuggers such as IMM, Kd and WinDbg. User level debuggers invoke the service usually by

 NTSTATUS DebugService(UCHAR ServiceClass, PVOID arg1, PVOID arg2)

According to  [7], 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
  INT 2d

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 [7] (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 [9] (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 [9] 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):
  1. At line 4 of the function body, KiDispatchException reduces EIP by 1, if the Exception code is STATUS_BREAKPOINT (this happens when int 2dh and int 3 are invoked). Note that in [3], P. Ferrie gave an excellent explanation regarding why the code reduces EIP by 1!
  2. It calls KiDebugRoutine several times. KiDebugRoutine is a function pointer. It points to KdpTrap (if debug enabled set in BOOT.ini), otherwise KdpTrapStub (which does nothing). 
  3. KdpTrap/KiDebugRoutine is invoked first, and then user handler is invoked (given search frame is enabled), and then KiDebugRoutine is invoked second time if user handle did not finish the job
For the "user mode" (it's the user program which invokes int 2d):
  1. It first check if there is a user debugger not attached (by checking DEBUG_PORT). If this is the case, kernel debugging service KiDispatchException will be called first to handle the exception.
  2. Then there is a complex nested if-else statements which uses DbgkForwardException to forward the exception to user debugger. (Unfortunately, there are not sufficient documentations for these involved functions). Our guess is that DbgkForwardException is to invoke user debugger to handle exception and KiUserDipsatchException is called to search for frame based user handlers if user debugger could not handle it.
  3. If the Search Frames attribute is false, the above (1 and 2) are not tried at all. It is directly forwarded to user debugger (make it to try twice), and if not processed, terminate the user process.
Now let's look back to Ferrie's article [3] again. The following description is complex and we will verify it in our later experient (in part II). Here the "exception address" is the "EIP value of the context" (which to be copied back to user process), and the "EIP register value" is the real EIP value of the user process when the exception occurs.

"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 [3]: 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 [3], 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. We will verify this argument in our later experiments. In summary we want to consider the following factors in our experiments:

  1. How does the debug mode (enabled in boot.ini) affect the user debugger behavior?
  2. How would user defined handlers affect the behavior?
  3. In summary, is the behavior of IMM correct regarding the code at 0x413BD5?
We will explore them in our experiments in Part II of this serie.

References

[1] Guiseppe Bonfa, "Step-by-Step Reverse Engineering Malware: ZeroAccess / Max++ / Smiscer Crimeware Rootkit", Available at http://resources.infosecinstitute.com/step-by-step-tutorial-on-reverse-engineering-malware-the-zeroaccessmaxsmiscer-crimeware-rootkit/

[2] Tyler Shields, "Anti-Debugging - A Developer's View", Available at http://www.shell-storm.org/papers/files/764.pdf

[3] P. Ferrie, "Anti-Unpacker Tricks - Part Three", Virus Bulletin Feb 2009. Available at http://pferrie.tripod.com/papers/unpackers23.pdf, Retrieved 09/07/2011.

[4] M. Pietrek, "A Crash Course on the Depth of Win32Tm Structured Exception Handling," Microsoft System Journal, 1997/01. Available at http://www.microsoft.com/msj/0197/exception/exception.aspxhttp://www.microsoft.com/msj/0197/exception/exception.aspx.

[5] Intel, "Intel 64 and  IA-32 Architectures for Software Developers Manual (5 Volume)", Available at http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html

[6] Microsoft, "Lesson 8 - Interrupt and Exception Handling", MSDNAA. Available at
http://technet.microsoft.com/en-us/library/cc767887.aspx

[7] A. Almeida, "Kernel and Remote Debuggers", Developer Fusions. Available at
http://www.developerfusion.com/article/84367/kernel-and-remote-debuggers/

[8] Wikipedia, "Win32 Thread Information Block", Available at http://en.wikipedia.org/wiki/Win32_Thread_Information_Block.

[9] G. Nebbett, "Windows NT/2000 Native API Reference", pp. 439-441, ISBN: 1578701996.