Defeat debugger [ZT]

Source: Internet
Author: User
[Source] http://www.osix.net/modules/article? Id = 594
[Note] the first article is a random translation, which is posted randomly. After all, I did not say anything,
Thanks to lift of kanxue and encourage of linhanshi.
To this end, I have posted another article,
It is also simple, but because I am a newbie, there must be a lot of loopholes and disputes in the translation, so I am very eager to win everyone's laughter at the same time,
Don't forget to approve me and help me improve :).

[Translator] aalloverred

[Translation]

Defeat the debugger

This time we will look at how to make it difficult for others to track your code. What we will learn is about the debugger and how they work.
And how your program detects them.

-----------------------
Dodge debugger-protect your program
-----------------------
By Giovanni tropeano at 11/2004
For osix

<Document directory <

... Preface
... A Brief History of debuggers
... How does the debugger work?
... Tracking and how to beat it
... Escape the breakpoint

:::

Start with the following sentence --
Reference:
/You cannot or compile programs that cannot be cracked ./
However, this does not mean that it cannot be very difficult.

In this article, we will learn some anti-debugging skills. You can use them in your own programs.

The first article I wrote for osix discussed self-modifying code and trying to get rid of the debugger. What I want to discuss now is to beat (or at least
It becomes difficult) debugger.

: A Brief History of the debugger :::

Previously there was a debug.com, which was the first Windows debugger. It is part of the standard MS-DOS package, and today except
There are few other uses in learning Assembly. The debugger that is barely suitable for cracking first came along with 80286, but they cannot cause
Actual damage.

However, after 80386, the situation has changed. The main complexity is the software (Windows ?) A better debugger is needed.
As some debuggers become increasingly powerful, they began to become a programmer's threat. In the end of 1980s, SoftICE appeared on the stage
Protecting programs and their developers has brought a lot of trouble. Since then, SoftICE has been passed down as a hacker debugging tool.
Olly is increasingly common among the younger generation of hackers.

Now, the possibility of analyzing software makes it useless to confront hackers. At the same time, there are also threats from
Newbie, but I have read many "how to crack the program" problem sets (fortunately everyone can get these things) and am searching
People who want to practice things are new players looking for new challenges.

: How the debugger works :::

I don't know how the debugger works, so it is very important to understand how the debugger works.

All debuggers belong to the following two types:

. Use the debugging capability of the processor
Independent imitation processor to monitor the running of the tested program

So far, there is no high-level counterfeit debugger that can not be detected by or avoided by code.
It will not appear in the future.

The key is, Is it worthwhile to develop such a simulator? Because we have been able to step into the code, control the execution of commands at a specific address, and monitor
Point to a memory address (or input/output port), change the signal task, and so on. I don't think it is worthwhile. In any case, continue...

Well, next we will conduct some in-depth research and try to keep up with it.

The debugger checks whether the trap bit of the Flag register is 1. If yes, an int 1 exception is automatically generated after each command,
And the control is handed over to the debugger. From this we can see that the code can be checked (debugged) by analyzing the mark register. Therefore, the debugger is
Not found, it must identify the command to read the mark register, imitate its operation, and return zero for the trap mark.
Difficult to do, right?

There are four debugging registers:

1. dr0
2. DR1
3. Dr2
4. dr3

They store the linear addresses of four Detection Points. Of course, there is also a register that stores the condition for each point, which is dr7. when any
When a condition is true, the processor throws an int1 exception, and the control is handed over to the debugger. There are four conditions:

1. An instruction is executed.
2. The content of a memory address has been changed.
3. A memory address is read or changed, but not executed.
4. An input/output port is referenced.

Now we want to discuss the software breakpoint. The software breakpoint is the only thing that can be hidden only by a full simulator with a processor.
Code in bytes-0xcc is inserted into a command before trying to execute it will cause an int 0x3 exception. to find whether there is at least one
The program only needs to calculate the checksum. To do this, you can use mov, movs, lods,
Pop, CMP, CMPs, or any other command; no debugger can trace any of them (as far as I know !).

: Tracking, and how to beat it :::

Because the completely invisible debugger is only a "possibility", most of them can still be detected.
Most debuggers use a one-byte 0xcc code.

Let's look at a simple protection method:

List 1.c++ a simple protection solution

Int main (INT argc, char * argv [])
{
// Encrypted string "Hello, free world! "
Char S0 [] = "/x0c/X21/x28/x28/x2b/x68/x64/x02/x36/
/X21/X21/x64/x13/x2b/x36/x28/x20/X65/x49/x4e ";
_ ASM
{
Begincode:;
; Code start

Pusha; all common
; Registers are protected.
Lea EBX, S0; EBX = & S0 [0]
Getnextchar:; Start
XOR eax, eax; eax = 0;
Lea ESI, begincode; ESI = & begincode
Lea ECx, endcode; Code Length
Sub ECx, ESI; "being debugged" is also included
Harvestcrc:; Calculation
Lodsb; the next byte is loaded to Al.
Add eax, eax; Calculate the checksum.
Loop harvestcrc; until (-- CX> 0)
XOR [EBX], Ah; the next character is decrypted.
Inc ebx; pointer to the next character
CMP [EBX], 0; until the end of the string
Jnz getnextchar; Continue decryption
Popa; restores all registers.
Endcode:; end of the Code to be debugged
NOP; the breakpoint here is safe.
}
Printf (I S0); display string.
Return 0;
}

Take a closer look at this piece of code (note Note). After the program is started, the sentence "Hello, free world! "Will appear on the screen. But when it runs
In the debugger, even if only one breakpoint is set between inincode and endcode, some are like "jgnnm." dpgg "umpnf #0"
In this way, meaningless junk information will appear on the screen. No, is it? Now you have some ideas.
The Checksum calculation process is put in another thread to enhance this protection.

When it comes to threads, it needs to use special methods for things. For our mortals, we need to implement programs that run in several places at the same time.
A little difficult. Common debuggers have a weakness, that is, they debug each process separately and never debug at the same time. The following example
Demonstrate how to use this for protection.

Table 2. Thread weaknesses

// This function will be executed in another thread.
// It is used to change the case sensitivity of Characters in the user name string without knowing it.

Void my (void * Arg)
{
Int p = 1;
// This Pointer Points to the byte being encrypted.
// Note that encryption is not executed from the first byte,
// In that case, the breakpoint can be set at the beginning of the cache
// Escape detection.
// If it is not a linefeed '/N', execute.
While (char *) Arg) [p]! = '/N ')
{
// Is the next character not initialized? It is also waiting.
While (char *) Arg) [p] <0x20 );

// The fifth digit is flipped.
// This converts the case of Latin characters.
(Char *) Arg) [p] ^ = 0x20;

// Point to the next byte to be processed.
P ++;
}
}

Int main (INT argc, char * argv [])
{
Char name [100];
// Store the cache of user names

Char buff [100];
// Store the password Cache

// Enter 0 in the username cache.
// (Some compilers will do this, but not all .)
Memset (& name [0], 0,100 );

// Subprogram my is executed in another thread.
_ Beginthread (& my, null, (void *) & name [0]);

// Enter the user name.
Printf ("Enter name:"); fgets (& name [0], 66, stdin );

// Enter the password.
// Note: The second thread has sufficient time to enter the password.
// Convert all characters in the user name into uppercase and lowercase characters. This is concealed and will not analyze the program.
// Keep track of this point. In a debugger that is not good at reflecting the impact of various parts of the program
// This is especially true during debugging.
 
Printf ("Enter Password:"); fgets (& buff [0], 66, stdin );

// Compare the user name and password reference values.
//
If (! (Strcmp (& buff [0], "password/N ")
// Note: Because the user name entered is changed
// Use strcmp (& name [0], "osix/N "),
// Instead of strcmp (& name [0], "osix/N") to compare it.
// (This is not obvious at first glance .)

| Strcmp (& name [0], "osix/N ")))
// Correct user name and password
Printf ("User OK/N ");
Else
// Error: incorrect user name or password
Printf ("wrong user or password! /N ");

Return 0;
}

Let's take a look at the program in the list. The program seems to accept osix: password, but the actual answer is
It's osix: password. Let's take a closer look. After the user enters the user name, the second thread will be useful for Processing Memory.
The account name is cached and converted to uppercase and lowercase (except the first character ).
All other threads are working independently, and these other threads can freely interfere with being called.
The work of the Trial thread (for example, changing its code)... it is only now possible!

There are some things to consider here, because we already know that the thread can be controlled, but if the developer is protected
If there are more than four breakpoints, the debugging register will no longer be trusted, and we have to use 0xcc bytes.
It is easy to detect.

If structured exception handling (seh) is used in the program to be debugged, the debugger will
The situation gets worse, and the famous SoftICE is no exception. The commands being debugged will either "Beat" the debugger and
Released from the control of the debugger, or the control is handed over to the database exception, but it is only sufficient to drown out the call of several codes.
The attacker's service program then gives control to the program for processing.

However, compared with the previous SoftICE version, this situation has improved. In the past, SoftICE strictly controlled certain interruptions, such
The program is not allowed to perform the division by zero independently.

Let's look at some other code ?! The current example is run and debugged in any SoftICE version including 4.05 and earlier.
When the machine reaches the int C = C/(a-B) line, it will suddenly stop the execution and lose control of the program.
To correct the issue, you only need to set a breakpoint in the First Command of the _ blocks t block in advance.
Where can I find the position of this block? Hackers cannot have source code.

List 3. An example of structural Exception Handling
Int main (INT argc, char * argv [])
{

// Protected Block
_ Try {
Int A = 1;
Int B = 1;
Int C = C/(a-B );
// Perform the division by zero operation.
// Multiple commands are used because
// Most compilers encounter shapes such
// An error is returned when int A = A/0 is expressed;
// When SoftICE executes the following command, it loses
// Control of the program to be debugged. It falls into some
// Never get control but may mislead the code.
// If variables A and B are assigned the return values of some functions,
// Instead of the immediate number, the relationship between the two is equal.
// After the program is decompiled
// Not so obvious. The result is that hackers may waste time.
// Analyze useless code!
}

_ Handler T (exception_execute_handler)
{
// When the divisor is zero, the code here will obtain
// Control, but SoftICE cannot realize this situation.
// Replace it with the first command in _ blocks T.
// Set the breakpoint.
// To determine the address of block _ blocks t, the hacker must accurately point out
// How does seh support
// Implemented in the compiler.
}
}

For hackers, they must thoroughly study structural exceptions at the system level and at the debugger level when dealing with such protection.
How is this done? It is too heavy for an amateur hacker, isn't it?

Because seh implements different methods in different compilers, it is no wonder that SoftICE does not support it. This is true for programmers.
Good thing. It's too bad for the attacker!

Therefore, the previous examples are strongly resistant to interruptions and are also easy to implement.
It works well with an operating system.

::: Skip the breakpoint :::

A breakpoint on a system function is a powerful weapon owned by the attacker. Assume that a Protection attempts to open the key file. It is unique in windows.
One recorded procedure in the document is to call the createfile function (in fact, createfilea and createfilew correspond to files respectively.
(ASCII and Unicode). All other functions inherited from earlier Windows versions are only encapsulated.
Createfile.

With this knowledge, the hacker will set a breakpoint at the starting address of the function (this address is known to the hacker), so as to quickly locate and tune

The protection code of this function is used.

However, not all hackers know that there is another way to open a file: by calling

The zwcreatefile (or ntcreatefile) function, or directly locates the kernel by calling the int 0x2eh interrupt.
Yes, all functions in the kernel are like this. It is also useful to do this without any permissions. Such calls can even be

It is derived from program code.

These tricks won't stop the scammers for a long time. This is terrible. But it is worthwhile to put this small time bomb there (in the block

_ Try calls int 0x2e to interrupt ).

Now, how can we process the registration information (by convention, it is a serial number or secret) used to read user input in the user and GDI modules?
Code) function (for example, getwindowstext? Because we know that all these functions are based on the command push EBP/mov EBP, ESP
The command code can execute it separately, that is, it does not directly transmit the control to the function to start, but after three bytes (because
Push EBP will change the stack, and JMP instead of call must be used when control is passed.) This setting will not occur when the breakpoint starts from the function.
This kind of technique may make a skilled hacker go astray for the time being.

Breakpoint can be divided into two types: the breakpoint set by the developer in the program and the dynamic breakpoint set by the debugger itself. The first type is clear:
When control is transferred to the debugger somewhere necessary, _ ASM {int 0x3} must be used }.

The breakpoint set at any location of the program is a little complicated. The debugger will save the current value of the memory address at the specified location, and then
Write code 0xcc there. before exiting the debugging interruption, the debugger restores all locations to their original state and modifies the IP addresses stored in the stack.
(Otherwise, it will point to its center .)

Figure 1: Stack content when the interrupt subroutine is entered
--------
What are the disadvantages of the 8086 processor breakpoint mechanism? The most unpleasant thing is that the debugger must directly modify the generation when setting breakpoints.
Code.

In SoftICE, when a program is tracked using the step-by-step (F10 key) method, the breakpoint is implicitly located before the next instruction.
The Checksum used in the bad protection code.

The simplest solution is to trace one command and one command-of course, this is a joke; in this case, you must set a hardware breakpoint.

In a similar situation, our predecessors (hackers in the 1980 s) usually decrypt the program manually and then use the NOP command to decrypt the program.

In this way, no problem will occur during program debugging (if other traps are not used in protection ).

Previously, the decryption program was compiled in C (Pascal, basic) as an independent program. Now this work has become simple, because

It is possible to implement decryption in the anti-assembler.

Decryption is actually re-compiling the decryption program using the IDA-C language. In this case, the checksum from begincode to endcode is required
It must be calculated to calculate the sum of each byte and the lower byte used for the checksum to load the next character. The obtained value is used for an exclusive or operation.
Process the S0 string. All of these can be implemented using the following code (assuming there are already appropriate tags in the disassembly code ):

List 239. Re-implement decryption with IDA-C

Auto A; Auto P; Auto CRC; Auto ch;
For (P = locbyname ("S0"); byte (p )! = 0; P ++)
{
CRC = 0;

For (A = locbyname ("begincode"); A <(locbyname ("endcode"); a ++)
{
Ch = byte ();
// Because IDA does not support byte and word types
// (It is a pity). It must be involved in bitwise operations.
// The CRC low byte is cleared,
// Copy the CH content to it.

CRC = CRC & 0xffffff00;
CRC = CRC | ch;
CRC = CRC + CRC;
}
// Extract the high byte from CRC.
CRC = CRC & 0 xFFFF;
CRC = CRC/0x100;

// The next byte of the string is decrypted.
Patchbyte (p, byte (p) ^ CRC );
}

If IDA is not available, this process can also be implemented in hiew as follows:

Notrace.exe? W pe 00001040 A32 <editor> 28672? Hiew 6.04 (c) Sen
00401003: 83ec18 sub ESP, 018; "$"
00401006: 53 push EBX
00401007: 56 push ESI
00401008: 57 push EDI
00401009: b905000000 000005
0040100e: be30604000 [byte/forward] 406030; "@ '0"
00401013: 8d7de8 1> mov BL, Al | Ax = 0061 p] [-0018]
00401016: f3a5 2 add EBX, EBX | BX = 44c2
00401018: A4 3 | Cx = 0000
Run from here: 4 | dx = 0000
00401019: 6660 5 | Si = 0000 [0ffffe8]
0040101b: 8d9de8ffff 6 | di = 0000
00401021: 33c0
. 0040101b: 8d9de8ffffff
. 00401021: 33c0 XOR eax, eax
. 00401023: 8d3519104000 Lea ESI, [000401019]; <begincode
. 00401029: 8d0d40104000 Lea ECx, [000401040]; <endcode
. 0040102f: 2bce sub ECx, ESI
. 00401031: AC lodsb
00401032: 03c0 add eax, eax
00401034: e2fb loop 000001031
00401036: 3023 XOR [EBX], ah
00401038: 43 Inc EBX
00401039: 803b00 cmp B, [EBX], 000 ;""
0040103c: 75e3 JNE 000001021
0040103e: 6661 Popa
To here:
00401040: 90 NOP
00401041: 8d45e8 Lea eax, [EBP] [-0018]
00401044: 50 push eax
00401045: e80c000000 call 000001056
0040104a: 83c404 add ESP, 004
1 help 2 size 3 direct 4 clear 5 clrreg 6 7 exit 8 9 store 10 Load

Step 1: Calculate the checksum. After the file is loaded into hiew, find the required code snippet and press <enter> twice to convert it to assembly.

Mode. Press the combination key <F8> + <F5> to jump to the entry point, and you will find the main process of starting the code. Next, press the <F3> key to enter the text
File editing status. Use the combination key <Ctrl> + <F7> to call up the decryption and editing window (the combination key varies with the version). Then enter
The following code:

MoV BL, Al
Add EBX, EBX

Other registers can be used to replace EBX, but eax cannot be used, because hiew clears eax every time before reading the next byte.
Now move the cursor to the row 0x401019 and press the <F7> key to run the decryption process to the row 0x401040 (but this line is not included). If
If correct, the value 0x44 in the high byte BX is the checksum.

In step 2, the encrypted row (its offset, loaded with ESI) is found, and then it is different from 0x44 or. (press <F3> to switch to edit mode, and press
<Ctrl> + <F8> specify the key used for encryption, 0x44, and then press <F8> to execute the decryption program by row .)

Notrace.exe? W pe 00006040 <editor> 28672? Hiew 6.04 (c) Sen
00006030: 48 65 6C 6c-6f 2C 20 46-72 65 65 20-57 6f 72 6C hello, free world
00006040: 20 65 49 4e-00 00 00 00-7a 1B 40 00-01 00 00 00 ein Z $ @ $

The rest is to replace the XOR at 0x401036 with the NOP command. Otherwise, the XOR will destroy the decryption code (
Encryption once), the program will no longer work.

After removing the protection, when debugging the program, there will be no serious consequences within the required scope.

Okay, so far. Another article on compilation and debugging is very long, but I hope it is still useful.

Goodbye!

Trope

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.