Deep exploration compiler safety check

xiaoxiao2021-03-06  27

Deep exploration compiler safety check

Original, please refer to

Http://msdn.microsoft.com/visualc/default.aspx?pull=/library/en-us/dv_vstechart/html/vctchcompilersecurityChecksindepth.asp

Introduction Safety is a key concern of high quality software, the most scared, most misunderstood is the buffer overflow. Now, mentioning the buffer overflow is enough to stop people, listen carefully. Too frequently, the technical details are lost in the copy, most of them are worthy of concern about this basis. In order to solve this problem, Visual C .NET introduces a security check to help developers determine the buffer overflow.

What is the buffer overflow?

The buffer is a memory, usually in the form of an array. When there is no length of the argument, the boundary of the buffer may be written. If such a behavior occurs than the memory address of the buffer, it is called buffer overflow; similar, if such a behavior occurs lower than the memory address of the buffer, it is referred to as buffer overflow. The incidence of overflowing buffers is significantly less than buffer overflow, but as described later, it does happen. Buffer overflow to an injecting code that is running process is called a buffer overflow.

Some documentation functions, such as structf, gets, scanf, sprintf, strcat, etc., it is easy to be attacked by buffer overflow, so they do not recommend them. A simple example illustrates the risk of these functions:

INT Vulnerable1 (Char * PSTR) {

INT ncount = 0;

Char PBUFF [_MAX_PATH];

STRCPY (PBUFF, PSTR);

For (; pBUF; PBUFF )

IF (* PBUFF == '//') Ncount ;

Return ncount;

}

These code has a significant weakness - if the length of buffer pointed by PSTR is greater than _max_path, then the PBuffer parameter may overflow. If you include Assert (Strlen (PSTR) <_max_path, you can discover this error under the Debug version, but the release version is not. Use these easy-to-attack functions is considered bad practice. Technically, it is not easy to be attacked by the attack, such as Strncpy, Strncat, and Memcpy. The problem with these functions is the developer to verify the length of the buffer instead of the compiler. The following function demonstrates a universal error:

#define buflen 16

Void VulneRable2 (Void)

{

Wchar_t buf [buflen];

int R;

RET = MultibytetowideChar (CP_ACP, 0, "1234567890123456789", -1, buf, sizeof (buf));

Printf ("% D / N", RET);

}

In this case, the number of bytes is used to indicate the size of the buffer, not the number of characters, and the buffer overflow occurs. In order to correct this attack point, the last parameter of MultibyToDechar is used to use SizeOf (BUF) / SizeOf (BUF [0]). VulneRable1 and Vulnerable2 are universal errors and can be easily prevented. However, these potential security vulnerabilities may be released into the product if the code REVIEWER is negligent. That's why Visual C .NET introduces a security check, which prevents the buffer overflow from the VulneRable1 and VulneRable2 functions from being injected into malicious code to an application that is easy to be attacked. X86 stack analysis

To understand how to use buffer overflow and how to work security check, you must fully understand the layout structure of the stack. Under the X86 system, the stack is growing down, meaning the address of the newly created data is less than the address of the element in the stack. Each function creates a new, a stack frame with the following layout, pay attention to the high memory address at the top of the list:

· Function Parameters

· Function Return Address

· Frame Pointer

· Exception Handler Frame

LOCALLY DECLARED VARIABLES AND BUFFERS

Callee Save Registers

As can be seen from the above layout, the buffer overflows may overwrite the early variables, abnormal processing frames, stack frame pointers, return addresses, and function parameters allocated than the buffer. In order to take over the program, a value must be written into the data, the value of the data is loaded into the EIP register. The return address of the function is one such data. A typical buffer overflow is an overlay function returns an address, allowing the return instruction of the function to load the return address into the EIP.

The data elements are stored in the stack as follows. The function of the function is pressed into the stack before the function call. The parameters are pressed into the stack from right to left. The CALL instruction presses the return address of the function into the stack, which stores the current value of the EIP register. The stack frame pointer is the value of the previous EB register, and when the FPO optimization does not occur, it is pressed into the stack. Therefore, the stack frame pointer is not always in the stack. If the function includes try / catch or any other form of an exception processing structure, the compiler will contain exception handling information in the stack. Thereafter, it is a partial declared variable and allocated buffer. The order of these assignments may change according to optimization implementation. Finally, the registers saved by the caller such as ESI, EDI, EBX, if they are used when the function is executed.

Runtime check

The buffer overflows is the mistake of C, C programmers, is also the most dangerous. Visual C .NET provides a tool that allows developers to easily discover these errors and fix them during the development phase. The / GZ switch in Visual C 6.0 has been new in / RTC1 in Visual C .NET. / RTC1 switch is an alias of / RTSU, where s represents a stack check, u represents an uninitialized variable check. All buffers allocated in the stack set the label at the boundary. Therefore, the buffer overflows, the underflow can be captured. Although small buffer overflows may not change the execution of the program, it can change the nearby data, and this will not be aware.

Time check is helpful for developers who don't only want to write secure, and developers who care about writing the correct code. However, the runtime check is only working in the Debug version, which is never designed to be available in the product code. However, such a check in the product code has a significant value. Check if these runtime check requires a small portion of performance loss. As a result, Visual C .NET introduces the / GS switch. / GS switch

The / GS switch provides a "speted Bump" or cookie between the buffer and the returned address. If an overflow has overwrites the return address, then it also covers the cookie between the buffer and him, the new stack layout is as follows:

· Function Parameters

· Function Return Address

· Frame Pointer

· Cookie

· Exception Handler Frame

LOCALLY DECLARED VARIABLES AND BUFFERS

Callee Save

Cookies will check more in detail later. As these security checks, the implementation of the function has also changed. First, when a function is executed, the first instruction to be executed is in the prolog of the function. At least, proLog is a local variable allocation space in the stack, such as the following instructions:

SUB ESP, 20H

This instruction reserved 32 bytes of local variables in the function. When the function uses the / GS switch compiles, the function proLog will reserve additional 4 bytes, three as follows additional instructions:

SUB ESP, 24h

MOV Eax, DWORD PTR [___security_cookie (408040h)]

XOR EAX, DWORD PTR [ESP 24h]

MOV DWORD PTR [ESP 20H], EAX

ProLog includes an instruction to extract a cookie copy, followed by using the cookie and the return address, and finally store the cookie below the return address next to the return address. From the above, the function is actually executed normally. When the function returns, the last thing to execute is the Epilog of the function, which is opposite to ProLog. If there is no security check, it will recover the stack space, return, just like the following instructions:

Add ESP, 20H

RET

When using / GS compile, the security check is also placed in Epilog:

MOV ECX, DWORD PTR [ESP 20h]

XOR ECX, DWORD PTR [ESP 24h]

Add ESP, 24h

JMP __security_check_cookie (4010B2H)

Query the copy of the stack of cookies, then make XOR operations with the return address, the ECX register should include the same content as the original cookies stored in the __security_cookie variable. Then recover the stack space, then not the RET instruction, but execute the JMP instruction, jump to __security_check_cookie routine.

__security_check_cookie routines are very intuitive. If the cookie is not changed, it performs RET instructions and ends the function call. Otherwise, it calls the Report_Failure function, Report_Failure then calls __security_error_handler (_SecerR_buffer_overrun, null). These functions are defined in the source file seccook.c of the C run library (CRT). Error processor

Make these security checks to support support for CRT. When the security check fails, the control needs to be handed over to __security_error_handler, the following is its processing summary:

void __cdecl __security_error_handler (int code, void * data)

{

IF (user_handler! = NULL) {

__Try {

User_handler (Code, DATA);

} __except (exception_execute_handler) {}

} else {//...prepare outmsg ...

__CrtMessageBoxa (Outmsg, "Microsoft Visual C Runtime Library, MB_ok | MB_ICONHAND | MB_SETFOREGROUND | MB_TASKMODAL);

}

_exit (3);

}

By default, the security check failed application pops up the display information is the "Buffer Overrun Detected!" Dialog box, and terminates the application when the dialog is closed. The CRT library provides a different processor function that can better process buffers overflows to developers. Function __set_security_error_handler Install Handler by storing the processor provided by the variable user_handler. The following example shows:

Void __cdecl report_failure (int code, void * unused)

{

IF (code == _secerr_buffer_overrun)

Printf ("Buffer Overrun Detected! / N");

}

void main ()

{

_SET_SECURITY_ERROR_HANDLER (Report_Failure);

// More code Follows

}

When the buffer overflow occurs, a message will be printed to the console window instead of the pop-up message window. Although the user processor does not have a termination program, when the processor returns, __ security_error_handler terminates the program by calling _exit (3). Function __security_error_handler and _SET_SECURITY_ERROR_HANDAL in the custom of the CRT's secfail.c file

Discuss how it should be done in the user processor. An exception is thrown during the universal action. However, because the abnormal information is stored in the stack, the throwing exception will pass the control to the abnormal stack. To prevent this behavior, use TRY / __EXCEPT to capture all exceptions when calling a user function in the __ security_error_handler function, and then terminate the program. Developers should not call DebugBreak because it will cause exceptions, and should not call longjmp. The user processor should do report errors, and create a log as much as possible to fix this problem.

Sometimes developers may want to override functions __security_error_handler instead of using functions _SET_SECURITY_ERROR_HANDLER to achieve the same purpose. Overribness is easy, the main processor is very important, and if there is no correct implementation, the danger will be caused.

Cookie value

Cookie is a random number of the same size in the pointer, meaning under the X86 system, cookie is 4 bytes long. Its value is stored in the CRT global variable __security_cookie. Its value is initialized by a function __security_init_cookie in the CRT Seccinit.c file. Cookie's randomness comes from the counter of the CPU processor. Each image file (DLL compiled using / GS, exe) has a different cookie in loading. There may be two problems when using the / GS compiler switch compiler. First, does not contain CRT support

Will miss random cookies because CRT is initialized when __security_init_cookie is called. If the cookie is not initialized when loading, if there is a buffer overflow, the application is still possible to attack. In order to solve this problem, the application needs to be displayed when the application needs to be displayed __security_init_cookie. Second, call the documentation function to initialize

The legacy app may encounter an unpredictable security check failed. For example, the following example:

DLLLENTRYPOINT (...) {

Char buf [_max_path]; // a buffer what triggers security checks

...

_CRT_INIT ();

...

}

The problem is _CRT_INIT to change the value of the cookie that already exists safely. Because the value of the cookie is different when the function exits and the original value, the security check consider that the buffer overflow occurs. The solution is to avoid declating the buffer before calling _CRT_INIT. You can now use the _alloca to allocate buffers on the stack as an avoidance method, because if the function _alloca allocates buffers, the compiler does not generate security checks. This avoidance method is not guaranteed to apply in the later Visual C version.

Performance impact

The performance and safety check must be balanced. The Visual C Compiler is committed to reducing performance impact to minimal. In most cases, performance has no more than 2%. In fact, experience shows most of the application, including high-performance server-side programs, performance impact is minimal.

The most important factor that makes performance is not affected is that only those functions that are easily attacked will perform security checks. It is now easy to be affected by the attack to allocate a buffer in the stack. String buffer If you assign more than four bytes, 1 to 2 bytes of each element in the buffer are easily attacked. The small buffer is not easily attacked and the number of functions that limit the safety check is limited to the growth of the code. Most of the executables are slightly slightly smoking because the code generated by the / GS compilation.

example

Therefore, the / GS switch does not correct the buffer overflow, but it can prevent the attacker from attacking by the buffer. When VulneRable1, VulneRable2 is compiled with / GS switch, the overflow will not be utilized. The function of the buffer overflow occurs in the last action can be exempt from the attacked. Because if the overflow occurs in the early, security check or no chance execution, or if the security check itself has been attacked, like the following example.

Example 1

Class Vulnerable3 {

PUBLIC:

Int value;

Vulnerable3 () {value = 0;

Virtual ~ vulnerable3 () {value = -1;}

}

Void Vulnerable3 (Char * PSTR) {

Vulnerable3 * Vuln = new vulnerable3;

Char BUF [20];

STRCPY (BUF, PSTR);

DELETE VULN;

}

In this case, a pointer to an object containing a function is assigned in the stack. Because the object contains virtual functions, the object contains a VTable pointer. The supplier can provide a malicious PSTR and overflows BUF. The function returns before the DELETE operator calls VULN's virtual function. Calling needs to find a destructor in VTABLE, which has been taken over. Before the function returns, the program has been taken in the north, so the security check does not detect the buffer overflow. Example 2

Void Vulnerable4 (Char * BBUFF, IN CBBUFF) {

Char Bname [128];

Void (* func) () = myfunction;

Memcpy (BNAME, BBUFF, CBBUFF);

(func) ();

}

In this case, the function is easily modified by the pointer. When the compiler allocates a space for the two local variables, it places the FUNC variable before the BNAME. Because this layout optimizer can enhance the efficiency of the code. Unfortunately, this allows attackers to provide malicious values ​​for BBUFF. An attacker can also provide the value of CBBUFF, indicating the size of BBuff. The function ignores the verification CBBUFF is less than or equal to 128. Calling MEMCPY caused the buffer overflow to overwrite the value of the FUNC. Because the FUNC is first called before VulneRable4, the code has been attacked before the security check is performed.

Example 3

INT Vulnerable5 (Char * PSTR) {

Char BUF [32];

Char * Volatile PCH = PSTR;

STRCPY (BUF, PSTR);

Return * PCH == '/ 0';

}

INT Main (int Argc, char * argv []) {

__Try {VulneRable5 (Argv [1]);

__except (2) {return 1;}

Return 0;

}

This program shows a particularly difficult problem because it uses structural exception handling. As mentioned earlier, the function of using an exception handler will handle information, such as the appropriate exception handler, in the stack. In this example, the abnormality processing frame of the main function may be attacked because the function VulneRable 5 defects may be attacked. An attacker uses overflow BUF to destroy the exception handling frame of the PCH and MAIN functions. Because the VulneRable5 function will later reference the PCH, if the attacker covers its value of 0, this will cause access to an exception. During the stack deployment, the operating system finds the exception handler that handles the exception in the exception processing frame. Because the abnormality processing frame has been destroyed, the operating system may hand over the control of the program to any code provided by the attacker. Safety check will not be able to check such buffers overflow because the function is not returned normally.

Recently, some popular attacks are used to use exception handling. The most popular Code Red virus appeared in 2001. Window XP has created an environment, which will be more difficult to attack through exception handling, because the address of the exception handler is not in the stack, and the value of all registers is cleared before calling the exception handler.

Example 4

Void VulneRable6 (Char * PSTR) {

Char buf [_max_path];

INT * PNUM;

STRCPY (BUF, PSTR);

SSCANF (BUF, "% D", PNUM);

}

Not like the previous other example, when compiling this function with / GS switch, the attacker cannot simply overflow the control of the program through the buffer. If you want to get the control of the program, you need two phases to attack. PNUM will be assigned before the BUF allows it to be overwritten by any value provided by the PSTR. Attackers will have to choose four bytes to override. If the buffer rewrites exceeds the cookie, the processor supplied in the user_handle is provided or stored in __security_cookie The default processor will take over the program. If no cookie is overwritten, the attacker will select the return address of the function as a function that does not contain a security check. In this case, the execution of the program is normal, returned normally from the function, and does not realize the buffer overflow; after a period of time, the program is quietly taken. The code that is easy to be attacked may be affected by another attack, which occurs in the buffer overflow in the heap, which cannot be checked out by the / GS switch. A set of array crosses attacks, it is accessed to a certain position in the array, rather than continuously writing for arrays, such a problem / GS switch cannot be checked. An unknown array index can access any part of the memory without modifying the content of the cookie. Another unknown index is a symbol, no symbolic mismatch. If the index is a symbol integer, a simple verification index is less than the size of the array is not enough. Finally, the / GS switch cannot check the buffer overflow.

in conclusion

Obviously, the buffer overflow is a very critical defect in the application. There is no more important code that is compact, safe. Although most views believe that a small amount of buffer overflow is difficult to discover. In writing security code, / GS switches are very helpful to developers. However, it solves the problem of buffer overflow in the code. Although security checks prevent the buffer from being utilized to some extent, the program is still terminated, an attack of the service, especially server-side code. Using the / GS switch is a safe way to reduce the attack from the buffer overflow without realization.

Although there is a tool that can be marked with a code that may be attacked, such as discussed herein, they are all disadvantages. The good code REVIEW personnel checked the good code more reliable than anything. The of Michael Howard and David Leblanc provides a lot of other methods that can reduce the attacked approach.

转载请注明原文地址:https://www.9cbs.com/read-77076.html

New Post(0)