[ Black Fenix's Anti-Debugging Tricks ]
By Black Fenix


  Lesson 1- "How to detect if there is any breakpoint (BPX) in your functions"

[ ¿ WHAT IS A BREAKPOINT ? ]


"If you don't know what a breakpoint is, you should better take a look at the bullet.gif (296 bytes)tutes before you start with this lesson. Anyway I'm going to explain briefly what they are used for and what is a breakpoint. Breakpoints are one of the great things that any good debugger should give to a cracker, using a breakpoint, the cracker could mark a point in wich the debugger would stop the program execution and pass the control to him/her, the cracker could now examine the code and act accordingly with the situation. Breakpoints are often used with Windows API functions (i.e with MessageBoxA) this is one of the reasons to not inform the user with API functions or DDL functions if a protection error occurs.


[ ¿HOW A BREAKPOINT WORKS ?]


Breakpoints (BPX) always had worked in the same way during the long life of debuggers, when the user decides to set up a BPX in any code location, the user sends a command to the debugger (under bullet.gif (296 bytes)SoftIce: bpx code_address) the debugger replaces the first opcode at this location with the hexadecimal interrupt 3 opcode 'CCh'. Everytime this instruction is executed, the debugger recovers the control and it replaces de CCh opcode with the original one and shows the user the actual code. Now the user could continue tracing the program or he could examine/modify the registers,code or memory, this would lead to a total aniquilation of our protection system.It's clear that if we could detect if our code has BPX, we could abort the program execution due to a violation of the protection scheme (always without showing any message, take a look at my bullet.gif (296 bytes)advices).


[ ¿ HOW WE CAN DETECT BREAKPOINTS ?]


Well, this is something that we can easily do under assembler but in C it's a little more complicated, but not impossible. The theory is as follows: obtain a pointer to the first opcode of the function we want to check, read the first opcode, check if its equal to 'CCh' (INT 3) and act accordingly.The following is a little C snippet that detects is there is a BPX in the function MessageBoxA. This code works perfectly compiled with Visual C++, I haven't checked it with other compilers but it should work. This code can detect any debugger coz all of them act the same way, I have tested it with SoftIce 4.0 and Windows 9x and I haven't found any problem. To check this code, compile the program, set up a BPX under MessageBoxA (bpx MessageBoxA if you are using SoftIce) and run the program, then check it disabling the breakpoint.


#include <stdio.h>
#include <windows.h>

#pragma warning( disable : 4035 ) /* deactivates warning for function that does not return any value*/

/* Functions are declared as __inline, this causes the expansion of this code each time a function is invoked, this is to difficult the cracker work by using this function more than once time */

__inline bool IsBPX(void * address)
{
    _asm {

mov esi,address    // load function address
mov al,[esi]          
// load the opcode
cmp al,0xCC        
// check if the opcode is CCh
je BPXed              
// yes, there is a breakpoint
                          
// jump to return TRUE
xor eax,eax         
// FALSE,
jmp NOBPX          
// no breakpoint

BPXed:

mov eax,1              // breakpoint foundt
NOBPX:
    }
}

// Version 2, it does the same work but using a more camoufled way

__inline bool IsBPX_v2(void * address)
{
    _asm {

mov esi,address  
mov al,[esi]        
mov ah,0x66      
// loads ah with 66h (half CCh)
add ah,ah           
// add it to itself, it results to 0xCC, and check
cmp ah,al           
je BPXed
xor eax,eax      
  // no breakpoint
jmp NOBPX

BPXed:

mov eax,1          // breakpoint found
NOBPX:
    }
}

#pragma warning( default : 4035 ) // set the default warning value for function without return value

void main()
{
    void *addr;
    addr=MessageBox;

    if (IsBPX_v2(addr))
    {
        MessageBox(NULL,"Are you trying to crack this program ?","Message",MB_OK|MB_ICONEXCLAMATION);
    }
    else MessageBox(NULL,"Good guy you seem legal...","Message",MB_OK);
}


Well, is not difficult as you can see and its very effective, I don't think that the code needs to be more explained because the interesting parts are well commented, perhaps the addr var isn't needed but I think it looks a bit clear using it. Let's analize the bad and the good things about this method:

marcador.gif (1024 bytes)If the cracker detects the code that causes the BPX detection, he/she could write a little program or use and hex editor to search the instruction's opcodes and replace them to bypass the detection without having to modify them at each time, this is because the compiler will always generate the same opcode for this macros. We could solve this by wrriting multiple macro versions with different instructions.

marcador.gif (1024 bytes)The method is difficult to detect if we use a well written macro, the first macro is the more easiest to detect because the cmp al,0xcc instruction and probably it will be useless against and unexperienced cracker.

marcador.gif (1024 bytes)There is a way to detect the check for the breakpoint that many crackers don't know (now less of them), if we set up a BPM (Breakpoint on Memory Access) in the function that we suspect, the debugger will stop just after the opcode is readed. In the previous example we will do: BPM MessageBoxA R, this tells SoftIce to stop execution if anything tries to read the first byte of the MessageBoxA function, try it.

As you can see, any anti-debugging trick has its own anti-anti-debugging trick :=) . That's all for know, more at next lesson.


You are inside Reversed Minds pages.

por Mr. Silver / WKT!
La información aquí vertida es exclusivamente para uso educacional, no puedo hacerme responsable del uso que se haga de esta, por lo que atiendo a la honradez de cada uno :), recuerda que debes comprar el software que utilices :)