Definition 7.1 (Tampering and Tamperproofing). Let Id (P, E) and Ia (P, E) be predicates over a program P and the environment E in which it executes. P is successfully tamperproofed if, throughout the execution of P, Id (P, E) holds. It is successfully attacked if, at some point during the execution of P, Ia (P, E)∧not Id (P, E), holds and this is not detectable by P
Watermarking and tamperproofing are also related. In fact, if perfect tamperproofing were available, watermarking would be easy: Just watermark with any trivial algorithm, tamperproof, and by definition the attacker will not be able to destroy the mark! It’s precisely because we don’t have perfect tamperproofing that we need to worry about watermarking stealth: We have to assume that an attacker who can find a watermark will also be able to modify the program to destroy the mark.
- 1. If you both obfuscate and tamperproof your code, an attacker who, in spite of the tamperproofing, is able to extract the code still has to de-obfuscate it in order to understand it;
- 2. Code that you insert to test for tampering or affect a response to tampering must be obfuscated in order to prevent the attacker from easily discovering it.
Christian Collberg and Jasvir Nagra bring together techniques drawn from related areas of computer science, including cryptography, steganography, watermarking, software metrics, reverse engineering, and compiler optimization. Using extensive sample code, they show readers how to implement protection schemes ranging from code obfuscation and software fingerprinting to tamperproofing and birthmarking, and discuss the theoretical and practical limitations of these techniques
Here, we’ve set a breakpoint on the decrypt function such that, whenever we enter it, the cleartext media gets printed and execution continues. Technically, an attacker typically modifies the program with the intent to force it to choose a different execution path than the programmer intended. He can achieve this by:
- Removing code from and/or inserting new code into the executable file prior to execution;
- Removing code from and/or inserting new code into the running program;
- Affecting the runtime behavior of the program through external agents such as emulators, debuggers, or a hostile operating system.
A protected program can try to detect that it’s running under emulation, on a modified operating system, or inside a debugger, but this turns out to be hard to do reliably. For example, how can you detect that a user has turned back the system clock so as not to trigger your “license-expired” check?We will show a few popular techniques, but in practice, tamperproofing algorithms tend to focus on making sure that the program’s static code and data haven’t been changed, even if this certainly isn’t enough to ensure it’s running properly.