Objective C vs. C/C++: Getting the Message
A dev who works regularly with C/C++ examines how these languages differ from Objective-C and the implications of these differences.
Join the DZone community and get the full member experience.Join For Free
Most of the time, working in cybersecurity, when we're reverse engineering an application we're working either with C or C++. Both of these languages use function semantics for method or function calls. Objective C is different — instead of using function semantics, where you use a 'call' instruction to pass program execution and state to a specific section of memory, Objective C uses message passing semantics. Let's explore exactly what that is, and how it differs from function semantics. We'll start by outlining exactly what function semantics are and how they work. To do that, we'll need to outline use of the call instruction and name mangling in C++.
C code is pretty straightforward to analyze. A function call in C will look something like this:
Just a call instruction and an address. Now in a program, this could be an address in the program (for a local procedure) or an address in a global offset table (or similar construct) to access a shared library function. Either way, CALL does some very specific things — like JMP, CALL will begin execution at the location pointed to by the submitted address. It will also set up the stack prior to the call using conventions specific to the target processor architecture. This includes saving execution state in registers, the stack, or some combination thereof.
C++ code works similarly — class methods are called by address. There are additional complexities around checking the object vtable and how the class information is saved in a compiled function name (via that name mangling feature I mentioned), but the key point is that C++ code still uses function calls for class methods.
Objective C doesn't.
Objective C uses message passing instead of function calls. This increases the run-time cost of a given method invocation, usually a negligible amount, but in exchange provides a large amount of flexibility. A call into (or a message to) a given object makes a call into the Objective-C runtime using the function
objc_msgSend(id self, SEL op, ...) where
self is the object to which the message will be sent and the submitted selector (
SEL) is the message itself. This provides some interesting capabilities and additional NULL safety.
obj_msgSend(.) is a function that is always available to any Objective C program as it's supplied by the runtime itself. Because of this, you will never have a NULL pointer exception raised when passing a message to another class object as
objc_msgSend(.) can implement protections against these kinds of errors.
objc_msgSendcan validate data passed through the argument list as well.
You can also hook
objc_msgSend. This allows you to inject arbitrary behavior into an application at runtime. You can use this to trace messages in a program, for example.
Objective C is not only different syntactically, it is different in essential design. Swift is interesting as well, as it's designed and implemented using concepts from Objective C (and is backward compatible with it).
Opinions expressed by DZone contributors are their own.