Environment checks

Environment checks focus on the runtime context in which the app is running.

Know the environment your app is running in.

While integrity validation helps protect against the initial tampering with the app's code, environment checks help protect the execution of that code in potentially hostile environments.

Debugger attachment checks

Detecting an attached debugger and taking action can help obstruct dynamic analysis and prevent reverse engineering attempts. In Swift, the sysctl call can be used to query the kernel state and check if the process is being debugged:

import Foundation
// 1. Call sysctl and verify it succeeded.
var info = kinfo_proc()
var size = MemoryLayout.stride(ofValue: info)
var name = [CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid()]
let result = sysctl(&name, UInt32(name.count), &info, &size, nil, 0)
guard result == 0 else { fatalError("Failed making sysctl call with result: \(result)") }
// 2. Checks if the process is being debugged.
print("App is being debugged:", info.kp_proc.p_flag & P_TRACED != 0)

When a debugger presence is detected, an app may choose to halt its execution or make significant changes to its normal behavior.

Dynamic library checks

Checking the loaded dynamic libraries can help identify any unexpected libraries that are not part of the system or not statically linked.

Detecting an unexpected library does not always indicate that the app is being tampered with. For example, another authorized app or extension may legitimately use code injection to provide specific features. Additionally, the list and details of loaded libraries can vary across different versions of macOS.

In Swift, _dyld_image_count and _dyld_get_image_name functions can provide details of loaded dynamic libraries:

import Foundation
// 1. Iterate over all loaded images.
for i in 0 ..< _dyld_image_count() {
  // 2. Print the loaded image name at index.
  let image = _dyld_get_image_name(i)
  guard let image else { fatalError("Failed getting the #\(i) dyld image name") }
  print(String(cString: image))
}