We are doing our bests to protect our frameworks, however, we are developers and we perfectly understand, that there is no uncrackable software, but there are lots of ways to make attackers’ efforts significantly more time-consuming. So here are some our best-practice tips to do this:

  1. Inlining the code where activation status and trial state are checked.
  2. Adding checking code to some core places where main functionality should be performed.
  3. Using C/C++ functions with check code instead of Objective-C classes and methods, use C structures instead of Objective-C ivars and properties.
  4. Using name obfuscation for functions/variables that are connected to activation/trial check.
  5. Combining original system/Kevlar functions usage with previously saved (e.g. at startup) pointers to them in your check code:
// somewhere at start (e.g. in -applicationWillFinishLaunching:)
    BOOL (*isActivated_func_p)(NSInteger *) = &DMKIsApplicationActivated;
    // some check code (e.g. in -applicationDidFinishLaunching:)
    NSInteger kevlarError = NSIntegerMax;
    if (!(isActivated_func_p(&kevlarError) && kevlarError == DMKevlarNoError))
        // if DMKIsApplicationActivated returns YES then kevlarError must be DMKevlarNoError
        // not activated here