Tamper response mechanism

A tamper response mechanism introduces a delayed failure into a program in response to detected tampering with the program. The mechanism determines a manner of responding to the detected tampering. The manner of responding may include corrupting a global pointer or using other techniques. The mechanism also determines when to respond to the tampering and implements the response at the determined time.

BACKGROUND

Software tampering is a threat to software developers and consumers by raising software piracy and security concerns. Tamper-resistant software typically contains two functional components: a tamper detection component and a tamper response component. Each of these components can be created from one or more separate modules. The tamper detection component is responsible for detecting an attempt to tamper with the software. The tamper response component implements one or more actions in response to detection of an attempt to tamper with the software.

Many typical tamper-resistant systems focus on hiding the tamper-detection code (i.e., the code that verifies the program's integrity). However, these typical tamper-resistant systems place little emphasis on the tamper response component. Since hackers often look for the weakest link to defeat the tamper-resistant system, an inadequate tamper response component may be utilized by hackers.

Systems that do include a tamper response component often apply the tamper response component immediately after the tamper detection component identifies an attempt to tamper with the software. Further, many typical copy protection systems can be easily patched out by a hacker or other individual attempting to tamper with the software.

To improve the effectiveness of a tamper-resistant system, it is desirable to separate the process of tamper detection from the process of responding to the detected tampering.

SUMMARY

The systems and methods described herein respond to detected tampering with a program in a manner that reduces the chances of detection of the tamper response system by introducing delayed, probabilistic failures in the program. The tamper response system determines a manner of responding to the detected tampering. One manner of responding includes intentionally corrupting one or more global pointers in the program. The tamper response system also determines when to respond to the detected tampering. The response may occur at a future time and be associated with a particular event or function call. The tamper response system implements the selected response at the determined time or event.

DETAILED DESCRIPTION

The systems and methods described herein provide a tamper response system for a program that reduces the likelihood of detection of the tamper response system by introducing delayed, probabilistic failures in a program. These systems and methods corrupt certain parts of the software program's internal state at specifically-chosen locations such that the software program either fails or exhibits degraded performance. The tamper response system is blended into the software program, thereby making the system difficult for a hacker to detect.

As discussed herein, a software vendor typically develops software programs, maintains the program source code, and sells the software in the form of executable code. A legitimate user buys the software, in the form of executable code, from the vendor. A software pirate attempts to tamper with the software, for example to alter its normal operation or bypass a copy protection system.

FIG. 1illustrates a portion of an example computing environment100containing a tamper-resistant software module102and multiple host modules104,106,108, and110. In the example ofFIG. 1, tamper-resistant software module102includes a tamper detection module112and a tamper response module114. Tamper detection module112is responsible for detecting attempts to tamper with any of the host modules104-110or tamper-resistant software module102. Tamper response module114implements one or more functions in response to detecting an attempt to tamper with any of the host modules104-110. The functions implemented by tamper response module114may stop the tampering activity or render the tampered module unusable.

A particular tamper-resistant software module102can be coupled to any number of host modules. In the example ofFIG. 1, tamper-resistant software module102is coupled to application program104, library module106, device driver108, and operating system110. In alternate embodiments, tamper-resistant software module102may be coupled to additional host modules not shown inFIG. 1. Although one tamper-resistant software module102is shown inFIG. 1, other implementations may include two or more tamper-resistant software modules coupled to any number of host modules.

An example system contains one or more instances of detection code in each host module. These instances of detection code communicate with the response code via covert flags. Upon detecting tampering, the detection code sets one or more flags to inform the response module of the tampering. The covert flag can take the form of a complex data structure. In one detection system, a static checksum based on either the static program code or dynamic execution traces of the code is computed and stored in a secret location. The detection system computes the new checksum when programs are running in malicious hosts, and check whether the new checksum is identical to the old checksum.

The example system also contains multiple instances of response code in the tamper-resistant software module. In one implementation, the multiple instances of response code are mutually independent such that discovering one instance of response code does not easily lead to discovering other instances of response code. The response code instances are designed such that a hacker cannot easily locate the code and cannot easily backtrack to the detection code from the response code.

To improve the effectiveness of the tamper-resistant software module, the module utilizes the principles of separation in space, separation in time, stealth, and predictability. Separation in space refers to performing tamper detection in one part of the program and causing a failure in another part of the program. This separation in space increases the difficulty of locating the detection code. For example, by increasing the number of function calls that occur between tamper detection and program failure, little trace is left for a hacker to perform any analysis. Additionally, the function where the detection code resides is not generally in the current call stack when the failure happens such that the detection code is not discovered when a debugger provides information about the current call stack.

Separation in time refers to delaying the failure of the program for a period of time after the tampering is detected. For example, the delay period may range from a few minutes to several hours or longer. Alternatively, the delay may be determined by the number of instructions executed between tampering detection and failure of the program.

The principle of stealth refers to blending the tamper-response system into the program being protected such that automatic scanning tools will not easily identify the tamper-resistant code. The stealth of a particular tamper-resistant system is context-sensitive. To improve effectiveness, the program being protected has a high statistical similarity with the response code.

The principle of predictability refers to the fact that the program that has been tampered with should eventually fail with high probability. Additionally, certain controls are used to determine where the program fails, thereby avoiding failure at sensitive points of program execution.

In a particular embodiment, a tamper response system corrupts a program's internal state to cause the program to fail. Careful selection of which portion of the state to corrupt and when to corrupt the state provides spatial and temporal separations. The deliberate use of “programming bugs” satisfies the stealth principle because the “programming bugs” look like normal bugs in a program.

As described herein, a program can have three different types of sites: detection sites (where tamper detection occurs), corruption sites (where the internal state is corrupted), and failure sites (where the failure actually happens). Detection sites and corruption sites may be associated with one another or may be separated and communicate, for example, using covert flags.

Particular examples discussed herein corrupt a program's state by corrupting the program's own variables. In alternate embodiments, various other procedures are used to corrupt a program's state. By corrupting the program's own variables, the failure of the program is predictable due to the corruption of the program's internal state. Additionally, this approach is stealthy because the response code is just an ordinary variable assignment.

When corrupting a program's variable, not all variables are good candidates to cause failure of the program. Pointer variables are typically good candidates for such corruption. If a pointer is corrupted by setting it to a NULL pointer or a value out of the program's address space, dereference of this pointer would crash the program. Further, if the next dereference happens after some time period, the failure is delayed in time.

FIG. 2illustrates an example of using global pointers. In this example, “p” is a global pointer that is used by Module B (identified by reference number204) and Module C (identified by reference number206). However, pointer p is not touched by Module A (identified by reference number202). By corrupting pointer p in Module A, then the program will continue running until Module A has finished and the program switches to Module B or Module C. Thus, corrupting the global pointer p can result in a delayed failure of the program.

To deal with a possible shortage of global pointers, the program is transformed into a semantically equivalent program that contains a level of indirection to the existing global variables. In one example, the original program code is shown below in the left column and the transformed program code is shown below in the right column.

int a;int a;void f( ) {int *p_a = &a;a = 3;void f( ) {}*p_a = 3;void main ( ) {}f( );void main ( ) {printf(‘ ‘a = %i\n’ ’, a);f( );}printf(‘ ‘a = %i\n’ ’, *p_a);}
For the global variable “a”, a new pointer variable “p_a” is created. “p_a” is a global pointer variable. The value of p_a is initialized to the address of a. The system then replaces some or all uses of variable a by the dereference of the newly created pointer variable p_a. Applying this extra level of indirection to global variables allows any global variable to be used to create new pointers, thereby alleviating the shortage of global pointers. The failure behavior of the transformed program code is predictable. After p_a is corrupted, any use of variable p_a is a potential failure site. The extra level of indirection to global variables also provides control over where the program fails. For example, if it is desirable for the program to fail outside of a particular function (such as the “main” function), then variable a is not replaced with variable p_a in that particular function. The above process can be iterated to create multiple layers of references, such as p_p_a, which points to p_a, which points to global variable “a”.

In addition to determining which global pointer to corrupt, a determination is made regarding where to corrupt the selected global pointer. This determination can be made by an individual or by one or more processing systems or algorithms. To identify a location for corrupting the pointer, a search algorithm analyzes the program to find a good site to set the pointer (or pointers) to nonsensical values. When analyzing the program, the search algorithm uses functions as the basic unit during the search.

Corruption of global pointers can occur inside any function body. Thus, a function body is one possible corruption site. A failure site is a function where the program fails when the program reaches that function after pointer corruption. In the example of corrupting pointers, failure sites correspond to locations where the corrupted pointers are dereferenced. To identify good corruption sites, particular embodiments search the program space to find corruption sites and failure sites with large spatial and temporal separations between one another.

When selecting a failure site, a function is selected that is not in the current call stack when the program fails. Otherwise, a hacker could use a debugging tool to trace back from the failure site to the corruption site. A tool such as a call graph is useful in avoiding such attacks. An example program is provided below, and the corresponding call graph for the example program is shown inFIG. 3.

In one implementation, the example program shown above is corrupted by corrupting the pointer variable p_a. The function f is a failure site because it dereferences p_a. Since the program will fail in function f, the corruption should occur outside of function f. Additionally, the main function is not the corruption site because the main function should not be in the current call stack when the program fails in function f. In this implementation, the system excludes functions where the corrupted pointer variable is dereferenced, and excludes functions who are ancestors in the call graph of functions where failure can occur. This approach ensures that when the program fails, the corruption site is not in the call stack.

One approach for determining spatial and temporal separations between corruption and failure measures the average distance between two function calls in a dynamic function call and time trace. This information indicates how far a function is from the nearest failure sites (e.g., functions that dereference the pointer) in terms of both the number of function calls and time. Functions that are far from failure sites are selected as possible corruption sites.

FIG. 4illustrates an example system flow400associated with a program. The example program is “Winboard”, a chess program written in the C programming language. This particular program contains approximately 27,000 lines of C code and contains 297 global variables, which represent possible variables to corrupt. The Winboard program contains various source C files, such as winboard.c and backend.c. Each of these files is provided to a varusage module, which produces a “.use” file that identifies locations where global variables are used. Separate use files are linked together by a uselink module to produce a global use file. The source C files are also provided to a callgraph module that produces “.cg” files (also referred to as call graph files). Separate .cg files are linked together by a cglink module to produce a global call graph.

System flow400also illustrates the execution of profiling tools on the Winboard program to produce a dynamic trace. The dynamic trace records the order of entering and exiting functions as well as the corresponding timestamps. This trace is the input to the trmatrix module, which measures the average distance between two functions in terms of both elapsed time and the number of function calls, records the information into a matrix, and writes the matrix into a “.tr” file.

At this level in system flow400, winboard.use, winboard.cg, and winboard.tr are provided as inputs to a delayedfailure module, which selects appropriate global variables and appropriate corruption sites following the guidelines and procedures discussed herein. The delayedfailure module first computes a set of good corruption sites for each global variable, following the algorithm below, then randomly selects some global variables and good corruption sites. Finally, a corrupt module performs source-to-source transformation to first create a layer of indirection to selected global variables, when necessary, and then plant the corruption of the global pointers into selected functions (on the condition that tampering is detected).

The following algorithm (illustrated using pseudo code) selects good corruption sites for a global variable.

Input:a) example.c, with global variables g1, g2, . . . , gn;b) Function-distance matrix T;c) δ: Threshold for the distance between corruption and failuresites.Output: The set of good corruption sites Ci, for each gi.1:  Compute the call graph G of example.c2:  for each global variable gi, 1 ≦i ≦n do3:  Ci← the set of all functions in example.c4:  Identify the set of functions where the value of giis used, say{fil, . . . fim}5:  for each fij, 1 ≦j ≦m do6:   Remove from Ciall the ancestors of fijin the call graph G7:   for each f remaining in Cido8:    if T [f, fij] < δ then9:    remove f from Ci10:   end if11:  end for12:  end for13: Output Cifor the global variable gi14: end for

As discussed above, this systems and procedures discussed herein protect software by making the software exhibit the effect of delayed failure after tampering is detected. To remove the tamper-response code, a hacker has to trace back from the crash site to analyze what is corrupted and where the corruption happens. Since pointer values are intentionally corrupted, the hacker has to attempt to debug the program with pointer-related bugs, which is very difficult. The situation is made more difficult for the hacker because the hacker does not generally have access to the source code.

Additional delay between corruption and failure can be achieved using the following techniques. Instead of setting the pointer value to NULL, the system can corrupt the pointer by adding random offsets to the pointer. In this situation, the cumulative effect of several corruptions will most likely crash the program, and the delay will be increased by this technique. In another situation, user-behavior models are analyzed to identify user-activated functions that are rarely called. For example, if a certain function is called approximately once an hour, then associating the corruption with that function can significantly increase the delay.

FIG. 5is a flow diagram illustrating an embodiment of a procedure500for adding a tamper-response mechanism to a program. Initially, the procedure identifies global pointers associated with the program (block502) and selects a particular global pointer to intentionally corrupt (block504). For example, the procedure may use a parsing tool to parse the program to locate global pointers. Trace pointers are then used to determine when and how frequently the various global pointers are used. For example, it is generally desirable to select a pointer that is used frequently in normal program operation to make it difficult for a hacker to identify the pointer being corrupted. In one embodiment, a single global pointer is selected to be corrupted. In alternate embodiments, two or more global pointers are selected to be corrupted.

Procedure500continues by determining when to corrupt the selected global pointer (block506). The selected global pointer can be corrupted immediately (e.g., upon detection of the program tampering) or at a future time (e.g., corresponding to a future event or calling a particular function).

FIG. 6is a flow diagram illustrating an embodiment of a procedure600for responding to detection of tampering with a program. Initially, procedure600detects tampering with a program (block602). Block604then determines whether it is time to corrupt the selected pointer. If it is time to corrupt the selected pointer, block606corrupts the selected global pointer using one or more of the corruption techniques discussed herein. If it is not time to corrupt the selected pointer, the procedure waits until the appropriate time occurs.

Particular examples discussed herein terminate or “crash” a program using corrupted pointers. However, it will be appreciated that various other techniques may be used to accomplish the same result. In particular, any technique can be used that introduces covert and delayed tamper response into a program, regardless of the actual mechanism that causes the program to deviate from its “normal” execution.

In certain programming languages, such as C# and Java, pointers and global variables may not be available or may be limited to atypical usage. In these situations, other techniques are useful in separating the tamper detection activity from the tamper response activity. For example, set an array index to fall outside the array's limits, thereby causing an “array out-of-bounds error”. In another example, a variable in a loop-condition test is changed to result in an infinite (or at least very time-consuming) loop. These techniques may require implicit data-based links between the code at the detection site and the response site. Although global variables in C/C++ serve to create such connections, proper object-oriented design generally stipulates object isolation and tightly controlled data flow. However, some object fields (e.g., public static members in C#) serve essentially as global variables. Some applications also use dedicated namespaces and classes that encapsulate global data, which can also substitute for true global variables.

The number of opportunities for delayed responses can be increased by performing various semantically-equivalent code transformations that break object isolation. For example, a constant loop endpoint or an API-function argument is converted to a public static variable that can be modified to effect a tamper response. If a good response location does not contain suitable code, new code is added that references such variables, such as a new loop or a new system-API call.

Certain corruption techniques do not cause failures as predictably as pointer corruption. However, slow degradation of the program's performance can be even more difficult to identify and analyze than definite failures. Any particular response may not terminate the program, but if one or more checks continue to fail, the cumulative effect causes the program performance to degrade and should eventually make the program unusable. Both the checks and responses can be made probabilistic in terms of space-time separation and response action.

Additionally, a program can degrade its functioning via slowdown, high resource usage, and arbitrary incorrect operation, such as file corruption or graphics distortion. These techniques may be generic and automated for example, transforming program loops to include conditions that take increasingly longer time to satisfy, such as gradually incremented counters. Although such application-specific techniques require manual design and implementation, these techniques could be quite effective (e.g., a game where the player's movements and aim become increasingly erratic).

FIG. 7illustrates an example general computer environment700, which can be used to implement the techniques described herein. The computer environment700is only one example of a computing environment and is not intended to suggest any limitation as to the scope of use or functionality of the computer and network architectures. Neither should the computer environment700be interpreted as having any dependency or requirement relating to any one or combination of components illustrated in the example computer environment700.

Computer environment700includes a general-purpose computing device in the form of a computer702. Computer702can be, for example, a desktop computer, a handheld computer, a notebook or laptop computer, a server computer, a game console, and so on. The components of computer702can include, but are not limited to, one or more processors or processing units704, a system memory706, and a system bus708that couples various system components including the processor704to the system memory706.

Computer702typically includes a variety of computer readable media. Such media can be any available media that is accessible by computer702and includes both volatile and non-volatile media, removable and non-removable media.

The system memory706includes computer readable media in the form of volatile memory, such as random access memory (RAM)710, and/or non-volatile memory, such as read only memory (ROM)712. A basic input/output system (BIOS)714, containing the basic routines that help to transfer information between elements within computer702, such as during start-up, is stored in ROM712. RAM710typically contains data and/or program modules that are immediately accessible to and/or presently operated on by the processing unit704.

Computer702may also include other removable/non-removable, volatile/non-volatile computer storage media. By way of example,FIG. 7illustrates a hard disk drive716for reading from and writing to a non-removable, non-volatile magnetic media (not shown), a magnetic disk drive718for reading from and writing to a removable, non-volatile magnetic disk720(e.g., a “floppy disk”), and an optical disk drive722for reading from and/or writing to a removable, non-volatile optical disk724such as a CD-ROM, DVD-ROM, or other optical media. The hard disk drive716, magnetic disk drive718, and optical disk drive722are each connected to the system bus708by one or more data media interfaces725. Alternatively, the hard disk drive716, magnetic disk drive718, and optical disk drive722can be connected to the system bus708by one or more interfaces (not shown).

Any number of program modules can be stored on the bard disk716, magnetic disk720, optical disk724, ROM712, and/or RAM710, including by way of example, an operating system726, one or more application programs728, other program modules730, and program data732. Each of such operating system726, one or more application programs728, other program modules730, and program data732(or some combination thereof) may implement all or part of the resident components that support the distributed file system.

A user can enter commands and information into computer702via input devices such as a keyboard734and a pointing device736(e.g., a “mouse”) Other input devices738(not shown specifically) may include a microphone, joystick, game pad, satellite dish, serial port, scanner, and/or the like. These and other input devices are connected to the processing unit704via input/output interfaces740that are coupled to the system bus708, but may be connected by other interface and bus structures, such as a parallel port, game port, or a universal serial bus (USB).

A monitor742or other type of display device can also be connected to the system bus708via an interface, such as a video adapter744. In addition to the monitor742, other output peripheral devices can include components such as speakers (not shown) and a printer746which can be connected to computer702via the input/output interfaces740.

Computer702can operate in a networked environment using logical connections to one or more remote computers, such as a remote computing device748. By way of example, the remote computing device748can be a personal computer, portable computer, a server, a router, a network computer, a peer device or other common network node, and the like. The remote computing device748is illustrated as a portable computer that can include many or all of the elements and features described herein relative to computer702.

Logical connections between computer702and the remote computer748are depicted as a local area network (LAN)750and a general wide area network (WAN)752. Such networking environments are commonplace in offices, enterprise-wide computer networks, intranets, and the Internet.

When implemented in a LAN networking environment, the computer702is connected to a local network750via a network interface or adapter754. When implemented in a WAN networking environment, the computer702typically includes a modem756or other means for establishing communications over the wide network752. The modem756, which can be internal or external to computer702, can be connected to the system bus708via the input/output interfaces740or other appropriate mechanisms. It is to be appreciated that the illustrated network connections are exemplary and that other means of establishing communication link(s) between the computers702and748can be employed.

In a networked environment, such as that illustrated with computing environment700, program modules depicted relative to the computer702, or portions thereof, may be stored in a remote memory storage device. By way of example, remote application programs758reside on a memory device of remote computer748. For purposes of illustration, application programs and other executable program components such as the operating system are illustrated herein as discrete blocks, although it is recognized that such programs and components reside at various times in different storage components of the computing device702, and are executed by the data processor(s) of the computer.

Alternatively, portions of the framework may be implemented in hardware or a combination of hardware, software, and/or firmware. For example, one or more application specific integrated circuits (ASICs) or programmable logic devices (PLDs) could be designed or programmed to implement one or more portions of the framework.

Although the description above uses language that is specific to structural features and/or methodological acts, it is to be understood that the invention defined in the appended claims is not limited to the specific features or acts described Rather, the specific features and acts are disclosed as exemplary forms of implementing the invention.