Mach, which is conceptually a micro-kernel within the bigger of kernel of XNU, does not support the UNIX/BSD concept of a process. Instead, it handles tasks, which are container objects holding the ports (references) of the various threads and virtual memory.
Mach's task APIs are far more powerful than the common POSIX syscalls which deal with processes. These APIs can, for example, invade the task's memory (for both read and write) and even inject threads (similar to Windows' CreateRemoteThread(), which POSIX does not support). In OS X, it is fairly easy to get the task port of a process and vice versa, by using task_for_pid() (although at times taskgated needs to be involved). In iOS, the special entitlement of task_for_pid-allow() must be used. This can be done by preparing an entitlement Plist like the one here:
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>get-task-allow</key> <true/> <key>task_for_pid-allow</key> <true/> </dict> </plist>
and calling Saurik's ldid to sign the binary.
- ^ Mach is not a true MicroKernel, as XNU implements both Mach and the BSD layer in one single address space, making it more of a monolithic architecture. It is, however, conceptually a micro-kernel, as it is an underlying implementation dealing with the most basic primitives: threads, tasks, virtual memory objects, ports, exceptions, and the like. On top of Mach can be implemented higher APIs - as is the case with XNU's BSD - and these layers expose a more uniform API with more complex objects. Thus, BSD processes are mapped to Mach tasks. BSD signals are mapped to Mach exceptions, etc.