X hits on this document





72 / 120

conditions “if ( 1 == 1 )” and “if ( 1 == 2 )” implement opaque predicates because the

first always evaluates to true, and the second always to false. The essential element in

preventing decompilation with opaque predicates is to insert invalid instructions in the

else branch of an always-true predicate (or the if-body of an always false predicate).

Since the invalid instructions will never be reached during normal operation of the

program there is no impact on the program's operation. The obfuscation only interferes

with decompilation, where a naïve decompiler will evaluate both “possibilities” of the

opaque predicate and fail on attempting to decompile the invalid, unreachable

instructions. Fig. 8.1 illustrates how opaque predicates would be used to protect bytecode

from decompilation. Unfortunately, this technique, often used in protecting machine

code from disassembly, cannot be used with Java bytecode because of the presence of the

Java Bytecode Verifier in the JVM. Before executing bytecode, the JVM performs the

following checks using single-pass static analysis to ensure that the bytecode has not

been tampered with; to understand why this is beneficial, imagine bytecode being

executed as it's received over a network connection. [31] documents the following

checks made by the Java Bytecode Verifier:

Type correctness: arguments of an instruction, whether on the stack or in registers,

should always be of the type expected by the instruction.

No stack overflow or underflow: instructions which remove items from the stack

should never do so when the stack is empty (or does not contain at least the

number of arguments that the instruction will pop off the stack). Likewise,


Document info
Document views475
Page views476
Page last viewedThu Jan 19 19:36:09 UTC 2017