Shi Jie · 2016/05/18 11:56
0 x00 preface
In iOS, dylibs are dynamically injected through DYLDINSERTLIBRARIES. The best way to prevent dylibs from being injected into DYLDINSERTLIBRARIES is to add an empty restict section at compile time. Dyld checks for restict in the section when loading dynamic libraries Skip loading in that case. For details, see: Prevent tweak attachment,App has a trick; Hack App protection,tweak tweak
Some time ago, I found that a demo I wrote with restict could still be mounted by Cycript.
0 x01 cycript profile
Cycript is a powerful tool developed by Saurik that allows developers to interact with applications from the command line and view and modify them at run time. The underlying implementation is through Apple’S javascriptCore. framework to get through the bridge between iOS and javascript. Specific explanation, reference
0 x02 cycript structure
After cycript is installed, you can see the directory structure affected by cycript installation through Cydia
These are the only files mentioned, but there is also a Cynject executable under /usr/bin that is cycript-related, and later analysis will show that this program is the core file for injection. I here, through SCP to download these files to the local, convenient analysis.
0x03 Cycript main program
While analyzing the Cycript main program, I observed that an InjectLibrary function was called inside
#! c void InjectLibrary(int pid, int argc, const char *argv[]) { auto cynject(LibraryFor(reinterpret_cast<void *>(&main))); auto slash(cynject.rfind('/')); _assert(slash ! = std::string::npos); cynject = cynject.substr(0, slash) + "/cynject"; auto library(LibraryFor(reinterpret_cast<void *>(&MSmain0))); bool ios(false); for (decltype(header->ncmds) i(0); i ! = header->ncmds; ++i) { if (command->cmd == LC_VERSION_MIN_IPHONEOS) ios = true; command = shift(command, command->cmdsize); } _syscall(munmap(map, size)); // XXX: _scope auto length(library.size()); _assert(length >= 6); length -= 6; _assert(library.substr(length) == ".dylib"); library = library.substr(0, length); library += ios ? "-sim" : "-sys"; library += ".dylib"; #endif std::ostringstream inject; inject << cynject << " " << std::dec << pid << " " << library; for (decltype(argc) i(0); i ! = argc; ++i) inject << " " << argv[i]; _assert(system(inject.str().c_str()) == 0); }Copy the code
In the process of parsing, the program will check the environment before injecting code, and conduct string formatting splicing, construct a shell command, which is used to call system function parameters, to perform cynject injection function.
0x04 Cynject Injection Program
Next, analyze Cynject, as you can see in function subb308, and retrieve the process handle structure by calling taskFor_pid. Through this structure, you can have access to processes.
Here’s an example:
#! c mach_port_t rtask; task_for_pid(mach_task_self(), pid, &rtask);Copy the code
In order to make dylib in memory capable of execution, the program load dylib through the way of thread. Further down, you see that the process creates a suspended thread
Get the handle structure, request memory in the process space, map the dylib, write to the requested space.
So, the code logic looks something like this:
#! c vm_size_t codeSize = 124; vm_address_t rAddress; vm_allocate(rtask, &rAddress, codeSize, TRUE); vm_write(rtask, rAddress, &code, (mach_msg_type_number_t)codeSize); vm_protect(rtask, rAddress, codeSize, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);Copy the code
Finally, when dylib is fully loaded, start dylib restore and execute to get it running
Comb through the general process:
(1) Get PID process handle (2) create a suspended thread in PID (3) apply for a piece of memory in PID process for loading DYLIB (4) call RESUME to RESUME thread
OVER~
With that said, the process is almost done, so take a Dylib and test it out
Use LLDB to connect to the program and look at the memory loading module:
As you can see, our malicious dylib has been injected into the process.
0 x05 afterword.
There are some interesting things in Cycript that you can dig deeper into. In addition, the above content should not be used in your own enterprise app products. According to the principles of Apple appStore, the operation of calling private API and dynamic code injection will be removed.